/* 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 */ // // Runs FLARQ-like protocol over UI Packets // #define _CRT_SECURE_NO_DEPRECATE #include "CHeaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); extern int (WINAPI FAR *EnumProcessesPtr)(); #include #include #include "tncinfo.h" #include "bpq32.h" #define MAXARQ 10 #define DLE 0x10 #define SOH 1 #define STX 2 #define EOT 4 #define FEND 0xC0 #define FESC 0xDB #define TFEND 0xDC #define TFESC 0xDD #define TIMESTAMP 352 #define CONTIMEOUT 1200 #define AGWHDDRLEN sizeof(struct AGWHEADER) extern int (WINAPI FAR *GetModuleFileNameExPtr)(); //int ResetExtDriver(int num); int SemHeldByAPI; static int ProcessReceivedData(int bpqport); static int ProcessLine(char * buf, int Port); static VOID ProcessFLDigiPacket(struct TNCINFO * TNC, char * Message, int Len); VOID ProcessFLDigiKISSPacket(struct TNCINFO * TNC, char * Message, int Len); struct TNCINFO * GetSessionKey(char * key, struct TNCINFO * TNC); static VOID SendARQData(struct TNCINFO * TNC, PMSGWITHLEN Buffer, int Stream); VOID SendRPBeacon(struct TNCINFO * TNC); unsigned int CalcCRC(UCHAR * ptr, int Len); static VOID ARQTimer(struct TNCINFO * TNC); VOID QueueAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen); VOID SaveAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen); static VOID ProcessARQStatus(struct TNCINFO * TNC, int Stream, struct ARQINFO * ARQ, char *Input); VOID CheckFLDigiData(struct TNCINFO * TNC); static VOID SendPacket(struct TNCINFO * TNC, struct STREAMINFO * STREAM, UCHAR * Msg, int MsgLen); int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); VOID Send_AX_Datagram(PDIGIMESSAGE Block, DWORD Len, UCHAR Port); int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); VOID ProcessARQPacket(struct PORTCONTROL * PORT, MESSAGE * Buffer); char * strlop(char * buf, char delim); extern UCHAR BPQDirectory[]; extern char MYALIASLOPPED[10]; #define MAXMPSKPORTS 16 static BOOL GotMsg; static HANDLE STDOUT=0; extern int Blocksizes[10]; static char WindowTitle[] = "UIARQ"; static char ClassName[] = "UIARQSTATUS"; static int RigControlRow = 165; static int ExtProc(int fn, int port,unsigned char * buff) { PMSGWITHLEN buffptr; unsigned int txlen=0; struct TNCINFO * TNC = TNCInfo[port]; int Stream = 0; struct STREAMINFO * STREAM; if (TNC == NULL) return 0; // Port not defined // Look for attach on any call for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0) { // New Attach int calllen; STREAM->Attached = TRUE; calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall); STREAM->MyCall[calllen] = 0; STREAM->FramesOutstanding = 0; SetWindowText(STREAM->xIDC_STATUS, "Attached"); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); } } switch (fn) { case 7: // 100 mS Timer. for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (STREAM->NeedDisc) { STREAM->NeedDisc--; if (STREAM->NeedDisc == 0) { // Send the DISCONNECT TidyClose(TNC, Stream); } } } ARQTimer(TNC); return 0; case 1: // poll // See if any frames for this port for (Stream = 0; Stream <= MAXARQ; Stream++) { STREAM = &TNC->Streams[Stream]; if (STREAM->Attached) CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); if (STREAM->ReportDISC) { STREAM->ReportDISC = FALSE; buff[4] = Stream; return -1; } if (STREAM->PACTORtoBPQ_Q == 0) { if (STREAM->DiscWhenAllSent) { STREAM->DiscWhenAllSent--; if (STREAM->DiscWhenAllSent == 0) STREAM->ReportDISC = TRUE; // Dont want to leave session attached. Causes too much confusion } } else { int datalen; buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q); datalen=buffptr->Len; buff[4] = Stream; buff[7] = 0xf0; memcpy(&buff[8],buffptr->Data,datalen); // Data goes to +7, but we have an extra byte datalen += (MSGHDDRLEN + 1); PutLengthinBuffer((PDATAMESSAGE)buff, datalen); ReleaseBuffer(buffptr); return (1); } } if (TNC->PortRecord->UI_Q) { struct _MESSAGE * buffptr; int SendLen; char Reply[256]; int UILen; char * UIMsg; buffptr = Q_REM(&TNC->PortRecord->UI_Q); UILen = buffptr->LENGTH; UILen -= 23; UIMsg = buffptr->L2DATA; UIMsg[UILen] = 0; if (UILen < 129 && STREAM->Attached == FALSE) // Be sensible! { // >00uG8BPQ:72 TestA SendLen = sprintf(Reply, "u%s:72 %s", TNC->NodeCall, UIMsg); SendPacket(TNC, STREAM, Reply, SendLen); } ReleaseBuffer(buffptr); } return (0); case 2: // send Stream = buff[4]; STREAM = &TNC->Streams[Stream]; // txlen=(buff[6]<<8) + buff[5] - 8; txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - (MSGHDDRLEN + 1); // 1 as no PID; if (STREAM->Connected) { buffptr = GetBuff(); if (buffptr == 0) return (0); // No buffers, so ignore buffptr->Len = txlen; memcpy(buffptr->Data, &buff[8], txlen); C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); return (0); } else { buff[8 + txlen] = 0; _strupr(&buff[8]); if (_memicmp(&buff[8], "D\r", 2) == 0) { if (STREAM->Connected) TidyClose(TNC, buff[4]); STREAM->ReportDISC = TRUE; // Tell Node return 0; } // See if a Connect Command. if (toupper(buff[8]) == 'C' && buff[9] == ' ' && txlen > 2) // Connect { char * ptr; char * context; struct ARQINFO * ARQ = STREAM->ARQInfo; int SendLen; char Reply[80]; _strupr(&buff[8]); buff[8 + txlen] = 0; memset(ARQ, 0, sizeof(struct ARQINFO)); // Reset ARQ State ARQ->TXSeq = ARQ->TXLastACK = 63; // Last Sent ARQ->RXHighest = ARQ->RXNoGaps = 63; // Last Received ARQ->OurStream = Stream + 64; ARQ->FarStream = 64; // Not yet defined memset(STREAM->RemoteCall, 0, 10); ptr = strtok_s(&buff[10], " ,\r", &context); strcpy(STREAM->RemoteCall, ptr); //00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 SendLen = sprintf(Reply, "c%s:42 %s:24 %c 7 T60R5W10", STREAM->MyCall, STREAM->RemoteCall, ARQ->OurStream); ARQ->ARQState = ARQ_ACTIVE; ARQ->ARQTimerState = ARQ_CONNECTING; SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); SetWindowText(STREAM->xIDC_STATUS, "Connecting"); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_DIRN, "Out"); STREAM->Connecting = TRUE; return 0; } } return (0); case 3: Stream = (int)buff; STREAM = &TNC->Streams[Stream]; { // Busy if TX Window reached struct ARQINFO * ARQ = STREAM->ARQInfo; int Outstanding; Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (Outstanding > ARQ->TXWindow) return (1 | 1 << 8 | STREAM->Disconnecting << 15); // 3rd Nibble is frames unacked else return 1 << 8 | STREAM->Disconnecting << 15; } return 1 << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting case 4: // reinit return (0); case 5: // Close return 0; } return 0; } VOID UIHook(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffer, MESSAGE * ADJBUFFER, UCHAR CTL, UCHAR MSGFLAG) { PORT = GetPortTableEntryFromPortNum(PORT->HookPort->PORTNUMBER); if (PORT) ProcessARQPacket(PORT, Buffer); } static VOID UpdateStatsLine(struct TNCINFO * TNC, struct STREAMINFO * STREAM) { char Count[16]; sprintf(Count, "%d", STREAM->bytesRXed); SetWindowText(STREAM->xIDC_RXED, Count); sprintf(Count, "%d", STREAM->bytesTXed); SetWindowText(STREAM->xIDC_SEND, Count); sprintf(Count, "%d", STREAM->BytesResent); SetWindowText(STREAM->xIDC_RESENT, Count); sprintf(Count, "%d", STREAM->BytesAcked); SetWindowText(STREAM->xIDC_ACKED, Count); } static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) { int Len = sprintf(Buff, "" "" "FLDigi Status" "

FLDIGI Status

"); Len += sprintf(&Buff[Len], ""); Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); Len += sprintf(&Buff[Len], "", TNC->WEB_CHANSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_PROTOSTATE); Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); // Len += sprintf(&Buff[Len], "", TNC->WEB_RESTARTS); Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Channel State%s
Proto State%s
Traffic%s
TNC Restarts
"); Len += sprintf(&Buff[Len], "", TNC->WebBuffer); Len = DoScanLine(TNC, Buff, Len); return Len; } UINT UIARQExtInit(EXTPORTDATA * PortEntry) { int i, port; char Msg[255]; struct TNCINFO * TNC; char * ptr; struct PORTCONTROL * PORT; struct STREAMINFO * STREAM; srand((unsigned int)time(NULL)); port = PortEntry->PORTCONTROL.PORTNUMBER; ReadConfigFile(port, ProcessLine); TNC = TNCInfo[port]; if (TNC == NULL) { // Not defined in Config file sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n"); WritetoConsole(Msg); return (int) ExtProc; } for (i = 0; i Streams[i].ARQInfo = zalloc(sizeof(struct ARQINFO)); } TNC->Port = port; TNC->PortRecord = PortEntry; if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) memcpy(TNC->NodeCall, MYNODECALL, 10); else ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; PortEntry->PORTCONTROL.PROTOCOL = 10; PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream PortEntry->PORTCONTROL.UICAPABLE = 1; // Can send beacons PortEntry->PORTCONTROL.PORTQUALITY = 0; PortEntry->SCANCAPABILITIES = NONE; // Scan Control - None if (PortEntry->PORTCONTROL.PORTPACLEN == 0 || PortEntry->PORTCONTROL.PORTPACLEN > 128) PortEntry->PORTCONTROL.PORTPACLEN = 64; ptr=strchr(TNC->NodeCall, ' '); if (ptr) *(ptr) = 0; // Null Terminate TNC->Hardware = H_UIARQ; if (TNC->BusyWait == 0) TNC->BusyWait = 10; PortEntry->MAXHOSTMODESESSIONS = MAXARQ; i = 0; while (TNC->ARQPorts[i]) { PORT = GetPortTableEntryFromPortNum(TNC->ARQPorts[i]); PORT->UIHook = (FARPROCY)UIHook; PORT->HookPort = (struct PORTCONTROL *)PortEntry; i++; } TNC->WEB_MODE = zalloc(50); TNC->WEB_TRAFFIC = zalloc(100); PortEntry->PORTCONTROL.TNC = TNC; TNC->WebWindowProc = WebProc; TNC->WebWinX = 520; TNC->WebWinY = 500; TNC->WebBuffer = zalloc(5000); TNC->WEB_COMMSSTATE = zalloc(100); TNC->WEB_TNCSTATE = zalloc(100); TNC->WEB_CHANSTATE = zalloc(100); TNC->WEB_BUFFERS = zalloc(100); TNC->WEB_PROTOSTATE = zalloc(100); TNC->WEB_RESTARTTIME = zalloc(100); TNC->WEB_RESTARTS = zalloc(100); TNC->WEB_MODE = zalloc(50); TNC->WEB_TRAFFIC = zalloc(100); #ifndef LINBPQ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 560, 350, ForcedClose); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " MyCall", WS_CHILD | WS_VISIBLE, 5,6,79,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " DestCall", WS_CHILD | WS_VISIBLE, 85,6,79,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Status", WS_CHILD | WS_VISIBLE, 165,6,84,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Sent", WS_CHILD | WS_VISIBLE, 250,6,59,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Rxed", WS_CHILD | WS_VISIBLE, 310,6,59,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Resent", WS_CHILD | WS_VISIBLE, 370,6,59,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Acked", WS_CHILD | WS_VISIBLE, 430,6,59,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(WS_EX_STATICEDGE, "STATIC", " Dirn", WS_CHILD | WS_VISIBLE, 490,6,49,20, TNC->hDlg, NULL, hInstance, NULL); for (i = 0; i Streams[i]; STREAM->xIDC_MYCALL = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 5, 26 + i*20, 79, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_DESTCALL = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 85, 26 + i*20, 79, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_STATUS = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 165, 26 + i*20, 84, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_SEND = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 250, 26 + i*20, 59, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_RXED = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 310, 26 + i*20, 59, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_RESENT = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 370, 26 + i*20, 59, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_ACKED = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 430, 26 + i*20, 59, 20, TNC->hDlg, NULL, hInstance, NULL); STREAM->xIDC_DIRN = CreateWindowEx(WS_EX_CLIENTEDGE, "STATIC", "", WS_CHILD | WS_VISIBLE, 490, 26 + i*20, 49, 20, TNC->hDlg, NULL, hInstance, NULL); } TNC->ClientHeight = 360; TNC->ClientWidth = 560; MoveWindows(TNC); #endif i=sprintf(Msg,"UIARQ\n"); WritetoConsole(Msg); return ((int) ExtProc); } static int ProcessLine(char * buf, int Port) { UCHAR * ptr; char * p_ipad = 0; int BPQport; int len=510; struct TNCINFO * TNC; char errbuf[256]; strcpy(errbuf, buf); BPQport = Port; TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); TNC->Timeout = 50; // Default retry = 5 seconds TNC->Retries = 6; // Default Retries TNC->Window = 16; TNC->InitScript = malloc(1000); TNC->InitScript[0] = 0; // Read Initialisation lines while(TRUE) { strcpy(errbuf, buf); if (memcmp(buf, "****", 4) == 0) return TRUE; ptr = strchr(buf, ';'); if (ptr) { *ptr++ = 13; *ptr = 0; } if (_memicmp(buf, "TIMEOUT", 7) == 0) TNC->Timeout = atoi(&buf[8]) * 10; else if (_memicmp(buf, "RETRIES", 7) == 0) TNC->Retries = atoi(&buf[8]); else if (_memicmp(buf, "WINDOW", 6) == 0) TNC->Window = atoi(&buf[7]); else { char * ptr, * p_value, * p_port; int i; ptr = strtok(buf, "=\t\n\r"); p_value = strtok(NULL, " \t\n\r"); if (ptr == NULL) return (TRUE); if (*ptr =='#') return (TRUE); // comment if (*ptr ==';') return (TRUE); // comment if (_stricmp(ptr,"Ports") == 0) { int n = 0; p_port = strtok(p_value, " ,\t\n\r"); while (p_port != NULL) { i = atoi(p_port); if (i == 0) return FALSE; if (i > NUMBEROFPORTS) return FALSE; TNC->ARQPorts[n++] = i; p_port = strtok(NULL, " ,\t\n\r"); } } } if (GetLine(buf) == 0) return TRUE; } return FALSE; } static VOID SendPacket(struct TNCINFO * TNC, struct STREAMINFO * STREAM, UCHAR * Msg, int MsgLen) { DIGIMESSAGE Block = {0}; int Port = TNC->ARQPorts[0]; Block.CTL = 3; Block.PID = 0xF0; ConvToAX25(STREAM->RemoteCall, Block.DEST); Block.DEST[6] |= 0x80; // set Command Bit memcpy(Block.ORIGIN, MYCALL, 7); Block.L2DATA[0] = STREAM->ARQInfo->FarStream; memcpy(&Block.L2DATA[1], Msg, MsgLen); MsgLen += 1; Send_AX_Datagram(&Block, MsgLen + 2, Port); // Inulude CTL and PID } VOID ProcessFLDigiData(struct TNCINFO * TNC, UCHAR * Input, int Len, int Stream); VOID ProcessARQPacket(struct PORTCONTROL * PORT, MESSAGE * Buffer) { // ARQ Packet from KISS-Like Hardware struct TNCINFO * TNC = TNCInfo[PORT->PORTNUMBER]; UCHAR * Input; int Len; int Stream = Buffer->L2DATA[0] - 64; if (Stream < 0 || Stream > MAXARQ) return; // First Bytes is Stream Number (as ASCII Letter) Input = &Buffer->L2DATA[1]; Len = Buffer->LENGTH - 24; ProcessFLDigiData(TNC, Input, Len, Stream); } /* 00cG8BPQ:1025 G8BPQ:24 0 8 T60R6W108E06 00kG8BPQ:24 G8BPQ 4 85F9B 00cG8BPQ:1025 GM8BPQ:24 0 7 T60R5W1051D5 (128, 5) ,00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 00kG8BPQ:24 G8BPQ 5 89FCA First no sees to be a connection counter. Next may be stream 08s___ABFC 08tG8BPQ:73 xxx 33FA 00tG8BPQ:73 yyy 99A3 08dG8BPQ:90986C 00bG8BPQ:911207 call:90 for dis 91 for dis ack 73 for chat) 08pG8BPQ?__645E 00s_??4235 08pG8BPQ?__645E 00s_??4235 i Ident c Connect k Connect Ack r Connect NAK d Disconnect req s Data Ack/ Retransmit Req )status) p Poll f Format Fail b dis ack t talk a Abort o Abort ACK 00cG8BPQ:1025 G8BPQ:24 0 7 T60R5W10FA36 00kG8BPQ:24 G8BPQ 6 49A3A 08s___ABFC 08 ARQ:FILE::flarqmail-1.eml ARQ:EMAIL:: ARQ:SIZE::90 ARQ::STX //FLARQ COMPOSER Date: 09/01/2014 23:24:42 To: gm8bpq From: SubjectA0E0 08!: Test Test Message ARQ::ETX F0F2 08pG8BPQ!__623E 08pG8BPQ!__623E 08pG8BPQ!__623E */ static VOID ProcessFLDigiData(struct TNCINFO * TNC, UCHAR * Input, int Len, int Stream) { PMSGWITHLEN buffptr; struct STREAMINFO * STREAM = &TNC->Streams[Stream]; char CTRL = Input[0]; struct ARQINFO * ARQ = STREAM->ARQInfo; char Channel = Stream + 64; int SendLen; char Reply[80]; Input[Len] = 0; // Process Message // This processes eitrher message from the KISS or RAW interfaces. // Headers and RAW checksum have been removed, so packet starts with Control Byte // Only a connect request is allowed with no session, so check first if (CTRL == 'c') { // Connect Request char * call1; char * call2; char * port1; char * port2; char * ptr; char * context; char FarStream = 0; int BlockSize = 6; // 64 default int Window = TNC->Window; APPLCALLS * APPL; char * ApplPtr = APPLS; int App; char Appl[10]; struct WL2KInfo * WL2K = TNC->WL2K; TRANSPORTENTRY * SESS; if (Stream) return; // Shouldn't have Stream on Connect Request call1 = strtok_s(&Input[1], " ", &context); call2 = strtok_s(NULL, " ", &context); port1 = strlop(call1, ':'); port2 = strlop(call2, ':'); // See if for us for (App = 0; App < 32; App++) { APPL=&APPLCALLTABLE[App]; memcpy(Appl, APPL->APPLCALL_TEXT, 10); ptr=strchr(Appl, ' '); if (ptr) *ptr = 0; if (_stricmp(call2, Appl) == 0) break; memcpy(Appl, APPL->APPLALIAS_TEXT, 10); ptr=strchr(Appl, ' '); if (ptr) *ptr = 0; if (_stricmp(call2, Appl) == 0) break; } if (App > 31) if (strcmp(TNC->NodeCall, call2) !=0) if (strcmp(call2, MYALIASLOPPED) !=0) return; // Not Appl or Port/Node Call ptr = strtok_s(NULL, " ", &context); FarStream = *ptr; ptr = strtok_s(NULL, " ", &context); BlockSize = atoi(ptr); if (ARQ->ARQState > ARQ_CONNECTING) { // We have already received a connect request - just ACK it goto AckConnectRequest; } // Get a Session Stream = 1; while(Stream <= MAXARQ) { if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0) goto GotStream; Stream++; } // No free streams - send Disconnect return; GotStream: STREAM = &TNC->Streams[Stream]; ProcessIncommingConnect(TNC, call1, Stream, FALSE); SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; strcpy(STREAM->MyCall, call2); STREAM->ConnectTime = time(NULL); STREAM->bytesRXed = STREAM->bytesTXed = STREAM->BytesAcked = STREAM->BytesResent = 0; if (WL2K) strcpy(SESS->RMSCall, WL2K->RMSCall); ARQ = STREAM->ARQInfo; memset(ARQ, 0, sizeof(struct ARQINFO)); // Reset ARQ State ARQ->FarStream = FarStream; ARQ->TXSeq = ARQ->TXLastACK = 63; // Last Sent ARQ->RXHighest = ARQ->RXNoGaps = 63; // Last Received ARQ->ARQState = ARQ_ACTIVE; ARQ->OurStream = Stream + 64; STREAM->NeedDisc = 0; if (App < 32) { char AppName[13]; memcpy(AppName, &ApplPtr[App * sizeof(struct CMDX)], 12); AppName[12] = 0; // Make sure app is available if (CheckAppl(TNC, AppName)) { char Buffer[32]; int MsgLen = sprintf(Buffer, "%s\r", AppName); buffptr = GetBuff(); if (buffptr == 0) { return; // No buffers, so ignore } buffptr->Len = MsgLen; memcpy(buffptr->Data, Buffer, MsgLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); TNC->SwallowSignon = TRUE; // Save Appl Call in case needed for } else { STREAM->NeedDisc = 50; // 1 sec } } ARQ->TXWindow = Window; if (BlockSize < 4) BlockSize = 4; if (BlockSize < 9) BlockSize = 9; ARQ->MaxBlock = Blocksizes[BlockSize]; ARQ->ARQTimer = 1; // To force CTEXT to be Queued if (App == 32) { // Connect to Node - send CTEXT if (HFCTEXTLEN > 1) { buffptr = GetBuff(); if (buffptr) { buffptr->Len = HFCTEXTLEN; memcpy(buffptr->Data, HFCTEXT, HFCTEXTLEN); SendARQData(TNC, buffptr, Stream); } } } if (STREAM->NeedDisc) { // Send Not Avail buffptr = GetBuff(); if (buffptr) { buffptr->Len = sprintf(buffptr->Data, "Application Not Available\r"); SendARQData(TNC, buffptr, Stream); } } SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_STATUS, "ConPending"); SetWindowText(STREAM->xIDC_DIRN, "In"); AckConnectRequest: SendLen = sprintf(Reply, "k%s:24 %s %c 7", call2, call1, ARQ->OurStream); SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->ARQTimerState = ARQ_CONNECTACK; return; } // All others need a session // if (!STREAM->Connected && !STREAM->Connecting) // return; if (CTRL == 'k') { // Connect ACK char * call1; char * call2; char * port1; char * port2; char * ptr; char * context; char FarStream = 0; int BlockSize = 6; // 64 default int Window = 16; char Reply[80]; int ReplyLen; call1 = strtok_s(&Input[1], " ", &context); call2 = strtok_s(NULL, " ", &context); port1 = strlop(call1, ':'); port2 = strlop(call2, ':'); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session ptr = strtok_s(NULL, " ", &context); if (ptr) FarStream = *ptr; ptr = strtok_s(NULL, " ", &context); if (ptr) BlockSize = atoi(ptr); if (STREAM->Connected) goto SendKReply; // Repeated ACK STREAM->ConnectTime = time(NULL); STREAM->bytesRXed = STREAM->bytesTXed = STREAM->BytesAcked = STREAM->BytesResent = 0; STREAM->Connected = TRUE; ARQ->ARQTimerState = 0; ARQ->ARQTimer = 0; sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", STREAM->MyCall, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_MYCALL, STREAM->MyCall); SetWindowText(STREAM->xIDC_DESTCALL, STREAM->RemoteCall); SetWindowText(STREAM->xIDC_DIRN, "Out"); UpdateMH(TNC, STREAM->RemoteCall, '+', 'Z'); ARQ->ARQTimerState = 0; ARQ->FarStream = FarStream; ARQ->TXWindow = TNC->Window; ARQ->MaxBlock = Blocksizes[BlockSize]; ARQ->ARQState = ARQ_ACTIVE; STREAM->NeedDisc = 0; buffptr = GetBuff(); if (buffptr) { ReplyLen = sprintf(Reply, "*** Connected to %s\r", STREAM->RemoteCall); buffptr->Len = ReplyLen; memcpy(buffptr->Data, Reply, ReplyLen); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(STREAM->xIDC_STATUS, "Connected"); SendKReply: // Reply with status SendLen = sprintf(Reply, "s%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } // All others need a session //if (!STREAM->Connected) // return; if (CTRL == 's') { // Status if (Channel != ARQ->OurStream) return; // Wrong Session ARQ->ARQTimer = 0; // Stop retry timer Input[Len] = 0; ProcessARQStatus(TNC, Stream, ARQ, &Input[1]); return; } if (CTRL == 'p') { // Poll char * call1; char * context; call1 = strtok_s(&Input[1], " \x1A", &context); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session Debugprintf("Sending Poll Resp TX NOGaps High %d %d %d", ARQ->TXSeq, ARQ->RXNoGaps, ARQ->RXHighest); SendLen = sprintf(Reply, "s%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } else ARQ->TurnroundTimer = 15; // Allow us to send it all acked QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } if (CTRL == 'a') { // Abort. Send Abort ACK - same as char * call1; char * context; call1 = strtok_s(&Input[1], " :", &context); if (strcmp(call1, STREAM->RemoteCall) != 0) return; if (Channel != ARQ->OurStream) return; // Wrong Session SendLen = sprintf(Reply, "o%c%c%c", ARQ->TXSeq + 32, ARQ->RXNoGaps + 32, ARQ->RXHighest + 32); if (ARQ->RXHighest != ARQ->RXNoGaps) { int n = ARQ->RXNoGaps + 1; n &= 63; while (n != ARQ->RXHighest) { if (ARQ->RXHOLDQ[n] == 0) // Dont have it SendLen += sprintf(&Reply[SendLen], "%c", n + 32); n++; n &= 63; } } QueueAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); return; } if (CTRL == 'i') { // Ident return; } if (CTRL == 't') { // Talk - not sure what to do with these return; } if (CTRL == 'd') { // Disconnect Request char * call1; char * context; call1 = strtok_s(&Input[1], " ", &context); strlop(call1, ':'); if (strcmp(STREAM->RemoteCall, call1)) return; if (Channel != ARQ->OurStream) return; // Wrong Session // As the Disc ACK isn't repeated, we have to clear session now STREAM->Connected = FALSE; STREAM->Connecting = FALSE; STREAM->ReportDISC = TRUE; strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); ARQ->ARQState = 0; SendLen = sprintf(Reply, "b%s:91", STREAM->MyCall); ARQ->ARQTimerState = ARQ_WAITACK; SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->Retries = 2; return; } if (CTRL == 'b') { // Disconnect ACK char * call1; char * context; call1 = strtok_s(&Input[1], " ", &context); strlop(call1, ':'); if (strcmp(STREAM->RemoteCall, call1)) return; if (Channel != ARQ->OurStream) return; // Wrong Session ARQ->ARQTimer = 0; ARQ->ARQTimerState = 0; ARQ->ARQState = 0; if (STREAM->Connected) { // Create a traffic record hookL4SessionDeleted(TNC, STREAM); } STREAM->Connecting = FALSE; STREAM->Connected = FALSE; // Back to Command Mode STREAM->ReportDISC = TRUE; // Tell Node STREAM->Disconnecting = FALSE; strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); return; } if (CTRL == 'u') { // Beacon //>00uGM8BPQ:72 GM8BPQ TestingAD67 char * Call = &Input[1]; strlop(Call, ':'); UpdateMH(TNC, Call, '!', 0); return; } if (STREAM->Connected) { if (Channel != ARQ->OurStream) return; // Wrong Session if (CTRL >= ' ' && CTRL < 96) { // ARQ Data int Seq = CTRL - 32; int Work; // if (rand() % 5 == 2) // { // Debugprintf("Dropping %d", Seq); // return; // } buffptr = GetBuff(); if (buffptr == NULL) return; // Sould never run out, but cant do much else // Remove any DLE transparency Len -= 1; buffptr->Len = Len; memcpy(buffptr->Data, &Input[1], Len); STREAM->bytesRXed += Len; UpdateStatsLine(TNC, STREAM); // Safest always to save, then see what we can process if (ARQ->RXHOLDQ[Seq]) { // Wot! Shouldn't happen ReleaseBuffer(ARQ->RXHOLDQ[Seq]); // Debugprintf("ARQ Seq %d Duplicate"); } ARQ->RXHOLDQ[Seq] = buffptr; // Debugprintf("ARQ saving %d", Seq); // If this is higher that highest received, save. But beware of wrap' // Hi = 2, Seq = 60 dont save s=h = 58 // Hi = 10 Seq = 12 save s-h = 2 // Hi = 14 Seq = 10 dont save s-h = -4 // Hi = 60 Seq = 2 save s-h = -58 Work = Seq - ARQ->RXHighest; if ((Work > 0 && Work < 32) || Work < -32) ARQ->RXHighest = Seq; // We may now be able to process some Work = (ARQ->RXNoGaps + 1) & 63; // The next one we need while (ARQ->RXHOLDQ[Work]) { // We have it C_Q_ADD(&STREAM->PACTORtoBPQ_Q, ARQ->RXHOLDQ[Work]); // ReleaseBuffer(ARQ->RXHOLDQ[Work]); ARQ->RXHOLDQ[Work] = NULL; // Debugprintf("Processing %d from Q", Work); ARQ->RXNoGaps = Work; Work = (Work + 1) & 63; // The next one we need } ARQ->TurnroundTimer = 200; // Delay before allowing reply. Will normally be reset by the poll following data return; } } } static VOID SendARQData(struct TNCINFO * TNC, PMSGWITHLEN Buffer, int Stream) { // Send Data, saving a copy until acked. struct STREAMINFO * STREAM = &TNC->Streams[Stream]; struct ARQINFO * ARQ = STREAM->ARQInfo; UCHAR TXBuffer[300]; SOCKET sock = TNC->TCPDataSock; int SendLen; UCHAR * ptr; int Origlen = Buffer->Len; ARQ->TXSeq++; ARQ->TXSeq &= 63; SendLen = sprintf(TXBuffer, "%c", ARQ->TXSeq + 32); ptr = Buffer->Data; // Start of data; ptr[Buffer->Len] = 0; memcpy(&TXBuffer[SendLen], Buffer->Data, Origlen); SendLen += Origlen; TXBuffer[SendLen] = 0; // if (rand() % 5 == 2) // Debugprintf("Dropping %d", ARQ->TXSeq); // else ARQ->TXHOLDQ[ARQ->TXSeq] = Buffer; STREAM->bytesTXed += Origlen; UpdateStatsLine(TNC, STREAM); // if waiting for ack, don't send, just queue. Will be sent when ack received if (ARQ->ARQTimer == 0 || ARQ->ARQTimerState == ARQ_WAITDATA) { SendPacket(TNC, STREAM, TXBuffer, SendLen); ARQ->ARQTimer = 15; // wait up to 1.5 sec for more data before polling ARQ->Retries = 1; ARQ->ARQTimerState = ARQ_WAITDATA; } else STREAM->BytesResent -= Origlen; // So wont be included in resent bytes } VOID TidyClose(struct TNCINFO * TNC, int Stream) { char Reply[80]; int SendLen; struct STREAMINFO * STREAM = &TNC->Streams[Stream]; struct ARQINFO * ARQ = STREAM->ARQInfo; SendLen = sprintf(Reply, "d%s:90", STREAM->MyCall); SaveAndSend(TNC, ARQ, TNC->TCPDataSock, Reply, SendLen); ARQ->ARQTimerState = ARQ_DISC; } VOID ForcedClose(struct TNCINFO * TNC, int Stream) { TidyClose(TNC, Stream); // I don't think Hostmode has a DD } VOID CloseComplete(struct TNCINFO * TNC, int Stream) { } static VOID SaveAndSend(struct TNCINFO * TNC, struct ARQINFO * ARQ, SOCKET sock, char * Msg, int MsgLen) { // Used for Messages that need a reply. Save, send and set timeout memcpy(ARQ->LastMsg, Msg, MsgLen + 1); // Include Null ARQ->LastLen = MsgLen; // Delay the send for a shot while // SendPacket(sock, Msg, MsgLen, 0); ARQ->ARQTimer = 1; ARQ->Retries = TNC->Retries + 1; // First timout is the real send return; } static VOID ARQTimer(struct TNCINFO * TNC) { PMSGWITHLEN buffptr; struct STREAMINFO * STREAM; struct ARQINFO * ARQ; int SendLen; char Reply[80]; int Stream; //Send frames, unless held by TurnroundTimer or Window int Outstanding; for (Stream = 0; Stream Streams[Stream]; ARQ = STREAM->ARQInfo; // TXDelay is used as a turn round delay for frames that don't have to be retried. It doesn't // need to check for busy (or anything else (I think!) if (ARQ->TXDelay) { ARQ->TXDelay--; if (ARQ->TXDelay) continue; SendPacket(TNC, STREAM, ARQ->TXMsg, ARQ->TXLen); } // if We are alredy sending (State = ARQ_WAITDATA) we should allow it to send more (and the Poll at end) if (ARQ->ARQTimerState == ARQ_WAITDATA) { while (STREAM->BPQtoPACTOR_Q) { Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(STREAM->BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (Outstanding >= ARQ->TXWindow) break; buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); SendARQData(TNC, buffptr, Stream); } ARQ->ARQTimer--; if (ARQ->ARQTimer > 0) continue; // Timer Still Running // No more data available - send poll SendLen = sprintf(Reply, "p%s", STREAM->MyCall); ARQ->ARQTimerState = ARQ_WAITACK; // This is one message that should not be queued so it is sent straiget after data Debugprintf("Sending Poll After Data"); memcpy(ARQ->LastMsg, Reply, SendLen + 1); ARQ->LastLen = SendLen; SendPacket(TNC, STREAM, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(STREAM->xIDC_STATUS, "Wait ACK"); continue; } // TrunroundTimer is used to allow time for far end to revert to RX if (ARQ->TurnroundTimer) ARQ->TurnroundTimer--; if (ARQ->TurnroundTimer == 0) { while (STREAM->BPQtoPACTOR_Q) { Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q) + 1; // Make sure busy is reported to BBS if (Outstanding >= ARQ->TXWindow) break; buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); SendARQData(TNC, buffptr, Stream); } } if (ARQ->ARQTimer) { // Only decrement if running send poll timer // if (ARQ->ARQTimerState != ARQ_WAITDATA) // return; ARQ->ARQTimer--; { if (ARQ->ARQTimer) continue; // Timer Still Running } ARQ->Retries--; if (ARQ->Retries) { // Retry Current Message SendPacket(TNC, STREAM, ARQ->LastMsg, ARQ->LastLen); ARQ->ARQTimer = TNC->Timeout + (rand() % 30); continue; } // Retried out. switch (ARQ->ARQTimerState) { case ARQ_WAITDATA: // No more data available - send poll SendLen = sprintf(Reply, "p%s", STREAM->MyCall); Debugprintf("Sending Poll After Timeout??"); ARQ->ARQTimerState = ARQ_WAITACK; // This is one message that should not be queued so it is sent straiget after data memcpy(ARQ->LastMsg, Reply, SendLen + 1); ARQ->LastLen = SendLen; SendPacket(TNC, STREAM, Reply, SendLen); ARQ->ARQTimer = TNC->Timeout; ARQ->Retries = TNC->Retries; strcpy(TNC->WEB_PROTOSTATE, "Wait ACK"); SetWindowText(STREAM->xIDC_STATUS, "Wait ACK"); continue; case ARQ_CONNECTING: // Report Connect Failed, and drop back to command mode buffptr = GetBuff(); if (buffptr) { buffptr->Len = sprintf((UCHAR *)&buffptr[2], "UIARQ} Failure with %s\r", STREAM->RemoteCall); C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); } // Send Disc to TNC in case it got the Connects, but we missed the ACKs TidyClose(TNC, Stream); ARQ->Retries = 2; // First timout is the real send, only send once STREAM->Connecting = FALSE; // Back to Command Mode ARQ->ARQState = FALSE; break; case ARQ_WAITACK: case ARQ_CONNECTACK: case ARQ_DISC: STREAM->Connected = FALSE; // Back to Command Mode STREAM->ReportDISC = TRUE; ARQ->ARQState = FALSE; while (STREAM->PACTORtoBPQ_Q) ReleaseBuffer(Q_REM(&STREAM->PACTORtoBPQ_Q)); while (STREAM->BPQtoPACTOR_Q) ReleaseBuffer(Q_REM(&STREAM->BPQtoPACTOR_Q)); strcpy(TNC->WEB_TNCSTATE, "Free"); strcpy(TNC->WEB_PROTOSTATE, "Disconncted"); SetWindowText(STREAM->xIDC_MYCALL, ""); SetWindowText(STREAM->xIDC_DESTCALL, ""); SetWindowText(STREAM->xIDC_DIRN, ""); SetWindowText(STREAM->xIDC_STATUS, ""); break; } } } } static VOID ProcessARQStatus(struct TNCINFO * TNC, int Stream, struct ARQINFO * ARQ, char * Input) { // Release any acked frames and resend any outstanding struct STREAMINFO * STREAM = &TNC->Streams[Stream]; int LastInSeq = Input[1] - 32; int LastRXed = Input[2] - 32; int FirstUnAcked = ARQ->TXLastACK; int n = strlen(Input) - 3; char * ptr; int NexttoResend; int First, Last, Outstanding; PMSGWITHLEN Buffer; int Acked = 0; // First status is an ack of Connect ACK if (ARQ->ARQTimerState == ARQ_CONNECTACK) { ARQ->Retries = 0; ARQ->ARQTimer = 0; ARQ->ARQTimerState = 0; strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(STREAM->xIDC_STATUS, "Connected"); } Debugprintf("Lsast In Seq, LastRXed %d %d", LastInSeq, LastRXed); // Release all up to LastInSeq while (FirstUnAcked != LastInSeq) { FirstUnAcked++; FirstUnAcked &= 63; Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } } ARQ->TXLastACK = FirstUnAcked; Outstanding = ARQ->TXSeq - ARQ->TXLastACK; if (Outstanding < 0) Outstanding += 64; TNC->PortRecord->FramesQueued = Outstanding + C_Q_COUNT(&STREAM->BPQtoPACTOR_Q); // Save for Appl Level Queued Frames if (FirstUnAcked == ARQ->TXSeq) { UpdateStatsLine(TNC, STREAM); ARQ->NoAckRetries = 0; strcpy(TNC->WEB_PROTOSTATE, "Connected"); SetWindowText(STREAM->xIDC_STATUS, "Connected"); return; // All Acked } // Release any not in retry list up to LastRXed. ptr = &Input[3]; while (n) { NexttoResend = *(ptr++) - 32; FirstUnAcked++; FirstUnAcked &= 63; while (FirstUnAcked != NexttoResend) { Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } FirstUnAcked++; FirstUnAcked &= 63; } // We don't ACK this one. Process any more resend values, then release up to LastRXed. n--; } // Release rest up to LastRXed while (FirstUnAcked != LastRXed) { FirstUnAcked++; FirstUnAcked &= 63; Buffer = ARQ->TXHOLDQ[FirstUnAcked]; if (Buffer) { Debugprintf("Acked %d", FirstUnAcked); STREAM->BytesAcked += Buffer->Len; ReleaseBuffer(Buffer); ARQ->TXHOLDQ[FirstUnAcked] = NULL; Acked++; } } // Resend anything in TX Buffer (From LastACK to TXSeq Last = ARQ->TXSeq + 1; Last &= 63; First = LastInSeq; while (First != Last) { First++; First &= 63; if(ARQ->TXHOLDQ[First]) { PMSGWITHLEN Buffer = ARQ->TXHOLDQ[First]; UCHAR TXBuffer[300]; SOCKET sock = TNC->TCPDataSock; int SendLen; Debugprintf("Resend %d", First); STREAM->BytesResent += Buffer->Len; SendLen = sprintf(TXBuffer, "%c", First + 32); memcpy(&TXBuffer[SendLen], Buffer->Data, Buffer->Len); SendLen += Buffer->Len; TXBuffer[SendLen] = 0; SendPacket(TNC, STREAM, TXBuffer, SendLen); ARQ->ARQTimer = 10; // wait up to 1 sec for more data before polling ARQ->Retries = 1; ARQ->ARQTimerState = ARQ_WAITDATA; if (Acked == 0) { // Nothing acked by this statis message Acked = 1; // Dont count more thna once ARQ->NoAckRetries++; if (ARQ->NoAckRetries > TNC->Retries) { // Too many retries - just disconnect TidyClose(TNC, Stream); return; } } } } UpdateStatsLine(TNC, STREAM); }