959 lines
19 KiB
C
959 lines
19 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
|
|
|
|
#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
|
|
|
|
char * strlop(char * buf, char delim);
|
|
UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen);
|
|
|
|
char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen);
|
|
UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen);
|
|
char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output);
|
|
|
|
|
|
DllExport int APIENTRY SetTraceOptions(int mask, int mtxparam, int mcomparam)
|
|
{
|
|
|
|
// Sets the tracing options for DecodeFrame. Mask is a bit
|
|
// mask of ports to monitor (ie 101 binary will monitor ports
|
|
// 1 and 3). MTX enables monitoring on transmitted frames. MCOM
|
|
// enables monitoring of protocol control frames (eg SABM, UA, RR),
|
|
// as well as info frames.
|
|
|
|
// *** For external use only, supports portnum up to 31 ***
|
|
|
|
MMASK = mask;
|
|
MTX = mtxparam;
|
|
MCOM = mcomparam;
|
|
|
|
return (0);
|
|
}
|
|
|
|
DllExport int APIENTRY SetTraceOptions64(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly)
|
|
{
|
|
|
|
// Sets the tracing options for DecodeFrame. Mask is a bit
|
|
// mask of ports to monitor (ie 101 binary will monitor ports
|
|
// 1 and 3). MTX enables monitoring on transmitted frames. MCOM
|
|
// enables monitoring of protocol control frames (eg SABM, UA, RR),
|
|
// as well as info frames.
|
|
|
|
// *** For external use only, supports portnum up to 63 ***
|
|
|
|
MMASK = mask;
|
|
MTX = mtxparam;
|
|
MCOM = mcomparam;
|
|
MUIONLY = monUIOnly;
|
|
|
|
return (0);
|
|
}
|
|
DllExport int APIENTRY SetTraceOptionsEx(int mask, int mtxparam, int mcomparam, int monUIOnly)
|
|
{
|
|
|
|
// *** For external use only, supports portnum up to 31 ***
|
|
|
|
// Sets the tracing options for DecodeFrame. Mask is a bit
|
|
// mask of ports to monitor (ie 101 binary will monitor ports
|
|
// 1 and 3). MTX enables monitoring on transmitted frames. MCOM
|
|
// enables monitoring of protocol control frames (eg SABM, UA, RR),
|
|
// as well as info frames.
|
|
|
|
|
|
MMASK = mask;
|
|
MTX = mtxparam;
|
|
MCOM = mcomparam;
|
|
MUIONLY = monUIOnly;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int IntSetTraceOptionsEx(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly)
|
|
{
|
|
|
|
// Sets the tracing options for DecodeFrame. Mask is a bit
|
|
// mask of ports to monitor (ie 101 binary will monitor ports
|
|
// 1 and 3). MTX enables monitoring on transmitted frames. MCOM
|
|
// enables monitoring of protocol control frames (eg SABM, UA, RR),
|
|
// as well as info frames.
|
|
|
|
|
|
MMASK = mask;
|
|
MTX = mtxparam;
|
|
MCOM = mcomparam;
|
|
MUIONLY = monUIOnly;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int APRSDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask)
|
|
{
|
|
return IntDecodeFrame(msg, buffer, Stamp, Mask, TRUE, FALSE);
|
|
}
|
|
DllExport int APIENTRY DecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp)
|
|
{
|
|
return IntDecodeFrame(msg, buffer, Stamp, MMASK, FALSE, FALSE);
|
|
}
|
|
|
|
int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask, BOOL APRS, BOOL MINI)
|
|
{
|
|
UCHAR * ptr;
|
|
int n;
|
|
MESSAGE * ADJBUFFER;
|
|
ptrdiff_t Work;
|
|
UCHAR CTL;
|
|
BOOL PF = 0;
|
|
char CRCHAR[3] = " ";
|
|
char PFCHAR[3] = " ";
|
|
int Port;
|
|
int MSGFLAG = 0; //CR and V1 flags
|
|
char * Output = buffer;
|
|
int HH, MM, SS;
|
|
char TR = 'R';
|
|
char From[10], To[10];
|
|
BOOL Info = 0;
|
|
BOOL FRMRFLAG = 0;
|
|
BOOL XIDFLAG = 0;
|
|
BOOL TESTFLAG = 0;
|
|
|
|
size_t MsgLen = msg->LENGTH;
|
|
|
|
// MINI mode is for Node Listen (remote monitor) Mode. Keep info to minimum
|
|
/*
|
|
KO6IZ*>K7TMG-1:
|
|
/ex
|
|
KO6IZ*>K7TMG-1:
|
|
b
|
|
KO6IZ*>K7TMG-1 (UA)
|
|
W0TX*>KC6OAR>KB9KC>ID:
|
|
W0TX/R DRC/D W0TX-2/G W0TX-1/B W0TX-7/N
|
|
KC6OAR*>ID:
|
|
*/
|
|
// Check Port
|
|
|
|
Port = msg->PORT;
|
|
|
|
if (Port & 0x80)
|
|
{
|
|
if (MTX == 0)
|
|
return 0; // TRANSMITTED FRAME - SEE IF MTX ON
|
|
|
|
TR = 'T';
|
|
}
|
|
|
|
Port &= 0x7F;
|
|
|
|
if ((((uint64_t)1 << (Port - 1)) & Mask) == 0) // Check MMASK
|
|
return 0;
|
|
|
|
|
|
// We now pass Text format monitoring from non-ax25 drivers through this code
|
|
// As a valid ax.25 address must have bottom bit set flag plain text messages
|
|
// with hex 01.
|
|
|
|
// GET THE CONTROL BYTE, TO SEE IF THIS FRAME IS TO BE DISPLAYED
|
|
|
|
if (msg->DEST[0] == 1)
|
|
{
|
|
// Just copy text (Null Terminated) to output
|
|
|
|
// Need Timestamp and T/R
|
|
|
|
Stamp = Stamp % 86400; // Secs
|
|
HH = (int)(Stamp / 3600);
|
|
|
|
Stamp -= HH * 3600;
|
|
MM = (int)(Stamp / 60);
|
|
|
|
SS = (int)(Stamp - MM * 60);
|
|
|
|
// Add Port: unless Mail Mon (port 64)
|
|
|
|
Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR);
|
|
|
|
strcpy(Output, &msg->DEST[1]);
|
|
Output += strlen(Output);
|
|
|
|
if (buffer[strlen(buffer) -1] == '\r')
|
|
Output--;
|
|
|
|
if (Port == 64)
|
|
Output += sprintf((char *)Output, " \r");
|
|
else
|
|
Output += sprintf((char *)Output, " Port=%d\r", Port);
|
|
|
|
return (int)strlen(buffer);
|
|
}
|
|
|
|
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;
|
|
|
|
if (MUIONLY)
|
|
if (CTL != 3)
|
|
return 0;
|
|
|
|
if ((CTL & 1) == 0 || CTL == FRMR || CTL == 3)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
if (((CTL & 2) && MINI) == 0) // Want Control (but not super unless MCOM
|
|
if (MCOM == 0)
|
|
return 0; // Dont do control
|
|
}
|
|
|
|
|
|
Stamp = Stamp % 86400; // Secs
|
|
HH = (int)(Stamp / 3600);
|
|
|
|
Stamp -= HH * 3600;
|
|
MM = (int)(Stamp / 60);
|
|
|
|
SS = (int)(Stamp - MM * 60);
|
|
|
|
// Add Port: if MINI mode and monitoring more than one port
|
|
|
|
if (MINI == 0)
|
|
Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR);
|
|
else
|
|
if (CountBits64(Mask) > 1)
|
|
Output += sprintf((char *)Output, "%d:", Port);
|
|
|
|
From[ConvFromAX25(msg->ORIGIN, From)] = 0;
|
|
To[ConvFromAX25(msg->DEST, To)] = 0;
|
|
|
|
Output += sprintf((char *)Output, "%s>%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;
|
|
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 *
|
|
}
|
|
}
|
|
|
|
if (MINI == 0)
|
|
Output += sprintf((char *)Output, " Port=%d ", Port);
|
|
|
|
// 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;
|
|
|
|
if (MINI == 0)
|
|
Output += sprintf((char *)Output, "<I%s%s S%d R%d>", CRCHAR, PFCHAR, NS, NR);
|
|
}
|
|
else if (CTL == 3)
|
|
{
|
|
// Un-numbered Information Frame
|
|
|
|
Output += sprintf((char *)Output, "<UI%s>", CRCHAR);
|
|
Info = 1;
|
|
}
|
|
else if (CTL & 2)
|
|
{
|
|
// UN Numbered
|
|
|
|
char SUP[6] = "??";
|
|
|
|
switch (CTL)
|
|
{
|
|
case SABM:
|
|
|
|
strcpy(SUP, "C");
|
|
break;
|
|
|
|
case SABME:
|
|
|
|
strcpy(SUP, "SABME");
|
|
break;
|
|
|
|
case XID:
|
|
|
|
strcpy(SUP, "XID");
|
|
XIDFLAG = 1;
|
|
break;
|
|
|
|
case TEST:
|
|
|
|
strcpy(SUP, "TEST");
|
|
TESTFLAG = 1;
|
|
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;
|
|
}
|
|
|
|
if (MINI)
|
|
Output += sprintf((char *)Output, "<%s>", SUP);
|
|
else
|
|
Output += sprintf((char *)Output, "<%s%s%s>", SUP, CRCHAR, PFCHAR);
|
|
}
|
|
else
|
|
{
|
|
// Super
|
|
|
|
int NR = (CTL >> 5) & 7;
|
|
char SUP[5] = "??";
|
|
|
|
switch (CTL & 0x0F)
|
|
{
|
|
case RR:
|
|
|
|
strcpy(SUP, "RR");
|
|
break;
|
|
|
|
case RNR:
|
|
|
|
strcpy(SUP, "RNR");
|
|
break;
|
|
|
|
case REJ:
|
|
|
|
strcpy(SUP, "REJ");
|
|
break;
|
|
case SREJ:
|
|
|
|
strcpy(SUP, "SREJ");
|
|
break;
|
|
}
|
|
|
|
Output += sprintf((char *)Output, "<%s%s%s R%d>", SUP, CRCHAR, PFCHAR, NR);
|
|
|
|
}
|
|
|
|
if (FRMRFLAG)
|
|
Output += sprintf((char *)Output, " %02X %02X %02X", ADJBUFFER->PID, ADJBUFFER->L2DATA[0], ADJBUFFER->L2DATA[1]);
|
|
|
|
if (XIDFLAG)
|
|
{
|
|
// Decode and display XID
|
|
|
|
UCHAR * ptr = &ADJBUFFER->PID;
|
|
|
|
if (*ptr++ == 0x82 && *ptr++ == 0x80)
|
|
{
|
|
int Type;
|
|
int Len;
|
|
unsigned int value;
|
|
int xidlen = *(ptr++) << 8;
|
|
xidlen += *ptr++;
|
|
|
|
// XID is set of Type, Len, Value n-tuples
|
|
|
|
// G8BPQ-2>G8BPQ:(XID cmd, p=1) Half-Duplex SREJ modulo-128 I-Field-Length-Rx=256 Window-Size-Rx=32 Ack-Timer=3000 Retries=10
|
|
|
|
|
|
while (xidlen > 0)
|
|
{
|
|
Type = *ptr++;
|
|
Len = *ptr++;
|
|
|
|
value = 0;
|
|
xidlen -= (Len + 2);
|
|
|
|
while (Len--)
|
|
{
|
|
value <<=8;
|
|
value += *ptr++;
|
|
}
|
|
switch(Type)
|
|
{
|
|
case 2: //Bin fields
|
|
case 3:
|
|
|
|
Output += sprintf((char *)Output, " %d=%x", Type, value);
|
|
break;
|
|
|
|
case 6: //RX Size
|
|
|
|
Output += sprintf((char *)Output, " RX Paclen=%d", value / 8);
|
|
break;
|
|
|
|
case 8: //RX Window
|
|
|
|
Output += sprintf((char *)Output, " RX Window=%d", value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 - (19 + sizeof(void *));
|
|
|
|
if (MsgLen < 0 || MsgLen > 257)
|
|
return 0; // Duff
|
|
|
|
while (MsgLen--)
|
|
{
|
|
C = *(ptr2++);
|
|
|
|
if (APRS)
|
|
*(ptr1++) = C; // MIC-E needs all chars
|
|
else
|
|
{
|
|
// 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);
|
|
|
|
break;
|
|
}
|
|
case NETROM_PID:
|
|
|
|
Output = DISPLAY_NETROM(ADJBUFFER, Output, (int)MsgLen);
|
|
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
|
|
|
|
n = ADJBUFFER->L2DATA[0]; // Frag Count
|
|
|
|
Output += sprintf((char *)Output, "<Fragmented IP %02x>\r", n);
|
|
|
|
if (ADJBUFFER->L2DATA[0] & 0x80) // First Frag - Display Header
|
|
{
|
|
Output = DISPLAYIPDATAGRAM((IPMSG *)&ADJBUFFER->L2DATA[2], Output, (int)MsgLen - 1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Output[-1] != 13)
|
|
Output += sprintf((char *)Output, "\r");
|
|
|
|
return (int)(Output - buffer);
|
|
|
|
}
|
|
// Display NET/ROM data
|
|
|
|
char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
|
|
{
|
|
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 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, " NODES broadcast from %s\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 - (19 + sizeof(void *));
|
|
|
|
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++) = 13;
|
|
*(Output++) = ' ';
|
|
Output = DISPLAYIPDATAGRAM((IPMSG *)ptr, Output, MsgLen);
|
|
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;
|
|
USHORT FRAGWORD;
|
|
|
|
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));
|
|
|
|
FRAGWORD = ntohs(IP->FRAGWORD);
|
|
|
|
if (FRAGWORD)
|
|
{
|
|
// If nonzero, check which bits are set
|
|
|
|
//Bit 0: reserved, must be zero
|
|
//Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.
|
|
//Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.
|
|
//Fragment Offset: 13 bits
|
|
|
|
if (FRAGWORD & (1 << 14))
|
|
Output += sprintf((char *)Output, "DF ");
|
|
|
|
if (FRAGWORD & (1 << 13))
|
|
Output += sprintf((char *)Output, "MF ");
|
|
|
|
FRAGWORD &= 0xfff;
|
|
|
|
if (FRAGWORD)
|
|
{
|
|
Output += sprintf((char *)Output, "Offset %d ", FRAGWORD * 8);
|
|
return Output; // Cant display proto fields
|
|
}
|
|
}
|
|
|
|
if (IP->IPPROTOCOL == 6)
|
|
{
|
|
PTCPMSG TCP = (PTCPMSG)&IP->Data;
|
|
|
|
Output += sprintf((char *)Output, "TCP Src %d Dest %d ", ntohs(TCP->SOURCEPORT), ntohs(TCP->DESTPORT));
|
|
return Output;
|
|
}
|
|
|
|
if (IP->IPPROTOCOL == 1)
|
|
{
|
|
PICMPMSG ICMPptr = (PICMPMSG)&IP->Data;
|
|
|
|
Output += sprintf((char *)Output, "ICMP ");
|
|
|
|
if (ICMPptr->ICMPTYPE == 8)
|
|
Output += sprintf((char *)Output, "Echo Request ");
|
|
else
|
|
if (ICMPptr->ICMPTYPE == 0)
|
|
Output += sprintf((char *)Output, "Echo Reply ");
|
|
else
|
|
Output += sprintf((char *)Output, "Code %d", ICMPptr->ICMPTYPE);
|
|
|
|
return Output;
|
|
}
|
|
|
|
/*
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output)
|
|
{
|
|
UCHAR * ptr = Datagram;
|
|
char 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 Reply %d.%d.%d.%d is at %s Tell %d.%d.%d.%d",
|
|
ptr[15], ptr[16], ptr[17], ptr[18], Dest, ptr[26], ptr[27], ptr[28], ptr[29]);
|
|
|
|
}
|