linbpq/AGWMoncode.c

655 lines
12 KiB
C

/*
Copyright 2001-2022 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
// Monitor Code - from moncode.asm
// Modified for AGW form monitor
#pragma data_seg("_BPQDATA")
#define _CRT_SECURE_NO_DEPRECATE
#include <stdlib.h>
#include <string.h>
#include <time.h>
#pragma data_seg("_BPQDATA")
#include "CHeaders.h"
#include "tncinfo.h"
// MSGFLAG contains CMD/RESPONSE BITS
#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND
#define RESP 2 // CURRENT MSG IS RESPONSE
#define VER1 1 // CURRENT MSG IS VERSION 1
#define UI 3
#define SABM 0x2F
#define DISC 0x43
#define DM 0x0F
#define UA 0x63
#define FRMR 0x87
#define RR 1
#define RNR 5
#define REJ 9
#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE
#define NETROM_PID 0xCF
#define IP_PID 0xCC
#define ARP_PID 0xCD
#define NODES_SIG 0xFF
UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, int msglen);
static UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen, int DoNodes);
static UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen);
static UCHAR * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output);
int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, int * FrameType, int useLocalTime, int DoNodes)
{
UCHAR * ptr;
int n;
MESSAGE * ADJBUFFER;
ptrdiff_t Work;
UCHAR CTL;
BOOL PF = 0;
char CRCHAR[3] = " ";
char PFCHAR[3] = " ";
int MSGFLAG = 0; //CR and V1 flags
char * Output = buffer;
char From[10], To[10];
BOOL Info = 0;
BOOL FRMRFLAG = 0;
BOOL XIDFLAG = 0;
BOOL TESTFLAG = 0;
size_t MsgLen = msg->LENGTH;
struct tm * TM;
if (useLocalTime)
TM = localtime(&Stamp);
else
TM = gmtime(&Stamp);
// GET THE CONTROL BYTE, TO SEE IF THIS FRAME IS TO BE DISPLAYED
n = 8; // MAX DIGIS
ptr = &msg->ORIGIN[6]; // End of Address bit
while ((*ptr & 1) == 0)
{
// MORE TO COME
ptr += 7;
n--;
if (n == 0)
{
return 0; // Corrupt - no end of address bit
}
}
// Reached End of digis
Work = ptr - &msg->ORIGIN[6]; // Work is length of digis
MsgLen -= Work;
ADJBUFFER = (MESSAGE *)((UCHAR *)msg + Work); // ADJBUFFER points to CTL, etc. allowing for digis
CTL = ADJBUFFER->CTL;
if (CTL & PFBIT)
PF = TRUE;
CTL &= ~PFBIT;
*FrameType = CTL;
Output += sprintf((char *)Output, " %d:Fm ", msg->PORT & 0x7f); // Mask TX bit
From[ConvFromAX25(msg->ORIGIN, From)] = 0;
To[ConvFromAX25(msg->DEST, To)] = 0;
Output += sprintf((char *)Output, "%s To %s", From, To);
// Display any Digi-Peaters
n = 8; // Max number of digi-peaters
ptr = &msg->ORIGIN[6]; // End of Address bit
while ((*ptr & 1) == 0)
{
// MORE TO COME
From[ConvFromAX25(ptr + 1, From)] = 0;
if (n == 8)
Output += sprintf((char *)Output, " Via %s", From); // Send via on first
else
Output += sprintf((char *)Output, ",%s", From);
ptr += 7;
n--;
if (n == 0)
break;
// See if digi actioned - put a * on last actioned
if (*ptr & 0x80)
{
if (*ptr & 1) // if last address, must need *
*(Output++) = '*';
else
if ((ptr[7] & 0x80) == 0) // Repeased by next?
*(Output++) = '*'; // No, so need *
}
}
*(Output++) = ' ';
// Set up CR and PF
CRCHAR[0] = 0;
PFCHAR[0] = 0;
if (msg->DEST[6] & 0x80)
{
if (msg->ORIGIN[6] & 0x80) // Both set, assume V1
MSGFLAG |= VER1;
else
{
MSGFLAG |= CMDBIT;
CRCHAR[0] = ' ';
CRCHAR[1] = 'C';
if (PF) // If FP set
{
PFCHAR[0] = ' ';
PFCHAR[1] = 'P';
}
}
}
else
{
if (msg->ORIGIN[6] & 0x80) // Only Origin Set
{
MSGFLAG |= RESP;
CRCHAR[0] = ' ';
CRCHAR[1] = 'R';
if (PF) // If FP set
{
PFCHAR[0] = ' ';
PFCHAR[1] = 'F';
}
}
else
MSGFLAG |= VER1; // Neither, assume V1
}
if ((CTL & 1) == 0) // I frame
{
int NS = (CTL >> 1) & 7; // ISOLATE RECEIVED N(S)
int NR = (CTL >> 5) & 7;
Info = 1;
Output += sprintf((char *)Output, "<I%s%s S%d R%d>", CRCHAR, PFCHAR, NS, NR);
}
else if (CTL == 3)
{
// Un-numbered Information Frame
//UI pid=F0 Len=20 >
Output += sprintf((char *)Output, "<UI pid=%02X Len=%d>", ADJBUFFER->PID, (int)MsgLen - 23);
Info = 1;
}
else if (CTL & 2)
{
// UN Numbered
char SUP[5] = "??";
switch (CTL)
{
case SABM:
strcpy(SUP, "C");
break;
case DISC:
strcpy(SUP, "D");
break;
case DM:
strcpy(SUP, "DM");
break;
case UA:
strcpy(SUP, "UA");
break;
case FRMR:
strcpy(SUP, "FRMR");
FRMRFLAG = 1;
break;
}
Output += sprintf((char *)Output, "<%s%s%s>", SUP, CRCHAR, PFCHAR);
}
else
{
// Super
int NR = (CTL >> 5) & 7;
char SUP[4] = "??";
switch (CTL & 0x0F)
{
case RR:
strcpy(SUP, "RR");
break;
case RNR:
strcpy(SUP, "RNR");
break;
case REJ:
strcpy(SUP, "REJ");
break;
}
Output += sprintf((char *)Output, "<%s%s%s R%d>", SUP, CRCHAR, PFCHAR, NR);
}
Output += sprintf((char *)Output, "[%02d:%02d:%02d]", TM->tm_hour, TM->tm_min, TM->tm_sec);
if (FRMRFLAG)
Output += sprintf((char *)Output, "%02X %02X %02X", ADJBUFFER->PID, ADJBUFFER->L2DATA[0], ADJBUFFER->L2DATA[1]);
if (Info)
{
// We have an info frame
switch (ADJBUFFER->PID)
{
case 0xF0: // Normal Data
{
char Infofield[257];
char * ptr1 = Infofield;
char * ptr2 = ADJBUFFER->L2DATA;
UCHAR C;
size_t len;
MsgLen = MsgLen - 23;
if (MsgLen < 0 || MsgLen > 257)
return 0; // Duff
while (MsgLen--)
{
C = *(ptr2++);
// Convert to printable
C &= 0x7F;
if (C == 13 || C == 10 || C > 31)
*(ptr1++) = C;
}
len = ptr1 - Infofield;
// Output[0] = ':';
Output[0] = 13;
memcpy(&Output[1], Infofield, len);
Output += (len + 1);
break;
}
case NETROM_PID:
Output = DISPLAY_NETROM(ADJBUFFER, Output,(int) MsgLen, DoNodes);
break;
case IP_PID:
Output += sprintf((char *)Output, " <IP>\r");
Output = DISPLAYIPDATAGRAM((IPMSG *)&ADJBUFFER->L2DATA[0], Output, (int)MsgLen);
break;
case ARP_PID:
Output = DISPLAYARPDATAGRAM(&ADJBUFFER->L2DATA[0], Output);
break;
case 8: // Fragmented IP
Output += sprintf((char *)Output, "<Fragmented IP>");
break;
}
}
if (Output == NULL)
return 0;
if (Output[-1] != 13)
Output += sprintf((char *)Output, "\r");
return (int)(Output - buffer);
}
// Display NET/ROM data
UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen, int DoNodes)
{
char Alias[7]= "";
char Dest[10];
char Node[10];
UCHAR TTL, Index, ID, TXNO, RXNO, OpCode, Flags, Window;
UCHAR * ptr = &ADJBUFFER->L2DATA[0];
if (ADJBUFFER->L2DATA[0] == NODES_SIG)
{
// Display NODES
if (DoNodes == 0)
return NULL;
// If an INP3 RIF (type <> UI) decode as such
if (ADJBUFFER->CTL != 3) // UI
return DisplayINP3RIF(&ADJBUFFER->L2DATA[1], Output, MsgLen - 24);
memcpy(Alias, ++ptr, 6);
ptr += 6;
Output += sprintf((char *)Output, "\rFF %s (NetRom Routing)\r", Alias);
MsgLen -= 30; //Header, mnemonic and signature length
while(MsgLen > 20) // Entries are 21 bytes
{
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
memcpy(Alias, ptr, 6);
ptr +=6;
strlop(Alias, ' ');
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
Output += sprintf((char *)Output, " %s:%s via %s qlty=%d\r", Alias, Dest, Node, ptr[0]);
ptr++;
MsgLen -= 21;
}
return Output;
}
// Display normal NET/ROM transmissions
Output += sprintf((char *)Output, " NET/ROM\r ");
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
TTL = *(ptr++);
Index = *(ptr++);
ID = *(ptr++);
TXNO = *(ptr++);
RXNO = *(ptr++);
OpCode = Flags = *(ptr++);
OpCode &= 15; // Remove Flags
Output += sprintf((char *)Output, "%s to %s ttl %d cct=%02X%02X ", Dest, Node, TTL, Index, ID );
MsgLen -= 20;
switch (OpCode)
{
case L4CREQ:
Window = *(ptr++);
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
Output += sprintf((char *)Output, "<CON REQ> w=%d %s at %s", Window, Dest, Node);
if (MsgLen > 38) // BPQ Extended Params
{
short Timeout = (SHORT)*ptr;
Output += sprintf((char *)Output, " t/o %d", Timeout);
}
return Output;
case L4CACK:
if (Flags & L4BUSY) // BUSY RETURNED
return Output + sprintf((char *)Output, " <CON NAK> - BUSY");
return Output + sprintf((char *)Output, " <CON ACK> w=%d my cct=%02X%02X", ptr[1], TXNO, RXNO);
case L4DREQ:
return Output + sprintf((char *)Output, " <DISC REQ>");
case L4DACK:
return Output + sprintf((char *)Output, " <DISC ACK>");
case L4INFO:
{
char Infofield[257];
char * ptr1 = Infofield;
UCHAR C;
size_t len;
Output += sprintf((char *)Output, " <INFO S%d R%d>", TXNO, RXNO);
if (Flags & L4BUSY)
*(Output++) = 'B';
if (Flags & L4NAK)
*(Output++) = 'N';
if (Flags & L4MORE)
*(Output++) = 'M';
MsgLen = MsgLen - 23;
if (MsgLen < 0 || MsgLen > 257)
return Output; // Duff
while (MsgLen--)
{
C = *(ptr++);
// Convert to printable
C &= 0x7F;
if (C == 13 || C == 10 || C > 31)
*(ptr1++) = C;
}
len = ptr1 - Infofield;
Output[0] = ':';
Output[1] = 13;
memcpy(&Output[2], Infofield, len);
Output += (len + 2);
}
return Output;
case L4IACK:
Output += sprintf((char *)Output, " <INFO ACK R%d> ", RXNO);
if (Flags & L4BUSY)
*(Output++) = 'B';
if (Flags & L4NAK)
*(Output++) = 'N';
if (Flags & L4MORE)
*(Output++) = 'M';
return Output;
case 0:
// OPcode zero is used for several things
if (Index == 0x0c && ID == 0x0c) // IP
{
// Output = L3IP(Output);
return Output;
}
if (Index == 0 && ID == 1) // NRR
{
Output += sprintf((char *)Output, " <Record Route>\r");
MsgLen -= 23;
while (MsgLen > 6)
{
Dest[ConvFromAX25(ptr, Dest)] = 0;
if (ptr[7] & 0x80)
Output += sprintf((char *)Output, "%s* ", Dest);
else
Output += sprintf((char *)Output, "%s ", Dest);
ptr +=8;
MsgLen -= 8;
}
return Output;
}
}
Output += sprintf((char *)Output, " <???\?>");
return Output;
}
/*
PUBLIC L3IP
L3IP:
;
; TCP/IP DATAGRAM
;
mov EBX,OFFSET IP_MSG
call NORMSTR
;
INC ESI ; NOW POINTING TO IP HEADER
*/
UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen)
{
UCHAR * ptr;
ptr = (UCHAR *)&IP->IPSOURCE;
Output += sprintf((char *)Output, "%d.%d.%d.%d>", ptr[0], ptr[1], ptr[2], ptr[3]);
ptr = (UCHAR *)&IP->IPDEST;
Output += sprintf((char *)Output, "%d.%d.%d.%d LEN:%d ", ptr[0], ptr[1], ptr[2], ptr[3], htons(IP->IPLENGTH));
/*
MOV AL,IPPROTOCOL[ESI]
CMP AL,6
JNE @F
MOV EBX, OFFSET TCP
CALL NORMSTR
JMP ADD_CR
@@:
CMP AL,1
JNE @F
MOV EBX, OFFSET ICMP
CALL NORMSTR
JMP ADD_CR
@@:
CALL DISPLAY_BYTE_1 ; DISPLAY PROTOCOL TYPE
; mov AL,CR
; call PUTCHAR
;
; MOV ECX,39 ; TESTING
;IPLOOP:
; lodsb
; CALL BYTE_TO_HEX
;
; LOOP IPLOOP
JMP ADD_CR
*/
return Output;
}
UCHAR * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output)
{
UCHAR * ptr = Datagram;
UCHAR Dest[10];
if (ptr[7] == 1) // Request
return Output + sprintf((char *)Output, " < ARP Request who has %d.%d.%d.%d? Tell %d.%d.%d.%d",
ptr[26], ptr[27], ptr[28], ptr[29], ptr[15], ptr[16], ptr[17], ptr[18]);
// Response
Dest[ConvFromAX25(&ptr[8], Dest)] = 0;
return Output + sprintf((char *)Output, " < ARP Rreply %d.%d.%d.%d? is at %s",
ptr[15], ptr[16], ptr[17], ptr[18], "??");
}