1250 lines
27 KiB
C
1250 lines
27 KiB
C
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <net/if.h>
|
|
#include <sys/ioctl.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <arpa/inet.h>
|
|
#if defined(__LINUX__)
|
|
# include <linux/wanpipe.h>
|
|
# include <linux/types.h>
|
|
# include <linux/if_packet.h>
|
|
# include <linux/if_wanpipe.h>
|
|
# include <linux/if_ether.h>
|
|
#else
|
|
# include <wanpipe_abstr.h>
|
|
# include <wanpipe.h>
|
|
# include <sdla_chdlc.h>
|
|
#endif
|
|
#include "fe_lib.h"
|
|
#include "wanpipemon.h"
|
|
|
|
#define X25_MOD8 0x01
|
|
#define X25_MOD128 0x10
|
|
|
|
#define PCAP_MAGIC 0xa1b2c3d4
|
|
|
|
extern trace_prot_t trace_prot_opt;
|
|
extern trace_prot_t trace_x25_prot_opt;
|
|
extern unsigned int TRACE_DLCI;
|
|
extern unsigned char TRACE_PROTOCOL;
|
|
extern unsigned int TRACE_X25_LCN;
|
|
extern unsigned char TRACE_X25_OPT;
|
|
extern char TRACE_EBCDIC;
|
|
extern char TRACE_ASCII;
|
|
extern char TRACE_HEX;
|
|
extern int sys_timestamp;
|
|
|
|
static char ebcdic[] =
|
|
{
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 40 */ ' ','.','.','.','.','.','.','.','.','.','[','.','<','(','+','!',
|
|
/* 50 */ '&','.','.','.','.','.','.','.','.','.',']','$','*',')',';','^',
|
|
/* 60 */ '-','/','.','.','.','.','.','.','.','.','|',',','%','_','>','?',
|
|
/* 70 */ '.','.','.','.','.','.','.','.','.','`',':','#','@','\'','=','"',
|
|
/* 80 */ '.','a','b','c','d','e','f','g','h','i','.','.','.','.','.','.',
|
|
/* 90 */ '.','j','k','l','m','n','o','p','q','r','.','.','.','.','.','.',
|
|
/* A0 */ '.','~','s','t','u','v','w','x','y','z','.','.','.','.','.','.',
|
|
/* B0 */ '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
|
|
/* C0 */ '{','A','B','C','D','E','F','G','H','I','.','.','.','.','.','.',
|
|
/* D0 */ '}','J','K','L','M','N','O','P','Q','R','.','.','.','.','.','.',
|
|
/* E0 */ '\\','.','S','T','U','V','W','X','Y','Z','.','.','.','.','.','.',
|
|
/* F0 */ '0','1','2','3','4','5','6','7','8','9','.','.','.','.','.','.',
|
|
};
|
|
|
|
|
|
int match_trace_criteria(unsigned char *pkt, int len, int *dlci);
|
|
void trace_banner (int len, unsigned char status, unsigned int timestamp, int *trace_started);
|
|
unsigned char hexdig(unsigned char n);
|
|
unsigned char dighex(unsigned char n);
|
|
int x25_call_request_decode (unsigned char *data, int len);
|
|
|
|
|
|
int match_trace_criteria(unsigned char *pkt, int len, int *dlci)
|
|
{
|
|
unsigned int tmp_val;
|
|
tmp_val=(pkt[0] >> 2)&0x3F;
|
|
tmp_val = tmp_val<<4;
|
|
tmp_val|=(pkt[1]>>4)&0x0F;
|
|
|
|
*dlci=tmp_val;
|
|
|
|
if (TRACE_DLCI > 0){
|
|
if (TRACE_DLCI == tmp_val){
|
|
return 0;
|
|
}
|
|
}else if (TRACE_DLCI == 0){
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
void trace_banner (int len, unsigned char status, unsigned int timestamp, int *trace_started)
|
|
{
|
|
if (!(*trace_started)){
|
|
unsigned char date_string[50];
|
|
|
|
date_string[0] = '\0';
|
|
|
|
sprintf(date_string, "%5d", timestamp);
|
|
|
|
if (sys_timestamp){
|
|
char tmp_time[10];
|
|
time_t time_val;
|
|
struct tm *time_tm;
|
|
|
|
/* Parse time and date */
|
|
time(&time_val);
|
|
time_tm = localtime(&time_val);
|
|
|
|
strftime(tmp_time,sizeof(tmp_time),"%m",time_tm);
|
|
sprintf(date_string+strlen(date_string), " | %s ",tmp_time);
|
|
|
|
strftime(tmp_time,sizeof(tmp_time),"%d",time_tm);
|
|
sprintf(date_string+strlen(date_string), "%s ",tmp_time);
|
|
|
|
strftime(tmp_time,sizeof(tmp_time),"%H",time_tm);
|
|
sprintf(date_string+strlen(date_string), "%s:",tmp_time);
|
|
|
|
strftime(tmp_time,sizeof(tmp_time),"%M",time_tm);
|
|
sprintf(date_string+strlen(date_string), "%s:",tmp_time);
|
|
|
|
strftime(tmp_time,sizeof(tmp_time),"%S",time_tm);
|
|
sprintf(date_string+strlen(date_string), "%s\t",tmp_time);
|
|
}
|
|
|
|
printf("\n%s : Len=%d\tTime Stamp=%s\n",
|
|
(status & 0x01) ?
|
|
"OUTGOING" : "INCOMING",
|
|
len,
|
|
date_string);
|
|
|
|
*trace_started=1;
|
|
}
|
|
}
|
|
|
|
|
|
unsigned char hexdig(unsigned char n)
|
|
{
|
|
n &= 0x0F;
|
|
/* only operate on the low four bits
|
|
* return a single hexadecmal ASCII digit */
|
|
return((n >= 10) ? (n - 10 + 'A') : (n + '0'));
|
|
}
|
|
|
|
|
|
unsigned char dighex(unsigned char n)
|
|
{
|
|
|
|
if (n >= 'a')
|
|
/* provide the adjustment if the passed ASCII value is greater */
|
|
return(n + 10 - 'a') ; /* than 'a' */
|
|
else
|
|
/* provide the adjustment if the passed ASCII value is greater */
|
|
/* than 'A' or is a numeral */
|
|
return((n >= 'A') ? (n + 10 - 'A') : (n - '0'));
|
|
}
|
|
|
|
|
|
int x25_call_request_decode (unsigned char *data, int len)
|
|
{
|
|
int len1, len2;
|
|
int i;
|
|
char addr1[16], addr2[16];
|
|
char udata[200];
|
|
char *first, *second;
|
|
char byte;
|
|
int localoffset;
|
|
int offset=3;
|
|
int facil_len;
|
|
unsigned char tmp_val;
|
|
|
|
byte = data[offset];
|
|
len2 = (byte >> 4) & 0x0F;
|
|
len1 = (byte >> 0) & 0x0F;
|
|
|
|
if ((len1+len2) > len){
|
|
return 1;
|
|
}
|
|
|
|
|
|
localoffset = ++offset;
|
|
byte = data[localoffset];
|
|
|
|
first=addr1;
|
|
second=addr2;
|
|
for (i = 0; i < (len1+len2); i++) {
|
|
if (i < len1) {
|
|
if (i % 2 != 0) {
|
|
*first++ = ((byte >> 0) & 0x0F) + '0';
|
|
localoffset++;
|
|
byte = data[localoffset];
|
|
} else {
|
|
*first++ = ((byte >> 4) & 0x0F) + '0';
|
|
}
|
|
} else {
|
|
if (i % 2 != 0) {
|
|
*second++ = ((byte >> 0) & 0x0F) + '0';
|
|
localoffset++;
|
|
byte = data[localoffset];
|
|
} else {
|
|
*second++ = ((byte >> 4) & 0x0F) + '0';
|
|
}
|
|
}
|
|
}
|
|
|
|
*first = '\0';
|
|
*second = '\0';
|
|
|
|
if (len1) {
|
|
printf("Called=%s ",addr1);
|
|
}
|
|
if (len2) {
|
|
printf("Calling=%s ",addr2);
|
|
}
|
|
|
|
localoffset = 4;
|
|
localoffset += ((len1 + len2 + 1) / 2);
|
|
|
|
if (localoffset >= len)
|
|
return 0;
|
|
|
|
/* Look for facilities */
|
|
facil_len=data[localoffset];
|
|
|
|
/* Skip facilites for now */
|
|
if (facil_len){
|
|
printf ("Facil=");
|
|
localoffset++;
|
|
|
|
for (i=0;i<facil_len ;i++){
|
|
printf("%02X",data[localoffset++]);
|
|
}
|
|
printf (" ");
|
|
}else{
|
|
localoffset++;
|
|
}
|
|
|
|
if (localoffset >= len)
|
|
return 0;
|
|
|
|
len1=localoffset;
|
|
|
|
first=udata;
|
|
byte=data[localoffset];
|
|
for (i=0;i<((len-len1)*2) && i<sizeof(udata);i++){
|
|
if (i % 2 != 0) {
|
|
tmp_val=(byte >> 0) & 0x0F;
|
|
*first++ = hexdig(tmp_val);
|
|
#if 0
|
|
if (tmp_val >= 0 && tmp_val <= 9){
|
|
*first++ = tmp_val + '0';
|
|
}else{
|
|
*first++ = tmp_val + 55;
|
|
}
|
|
#endif
|
|
localoffset++;
|
|
byte = data[localoffset];
|
|
} else {
|
|
tmp_val=(byte >> 4) & 0x0F;
|
|
*first++ = hexdig(tmp_val);
|
|
}
|
|
}
|
|
|
|
*first='\0';
|
|
printf("Data=%s",udata);
|
|
|
|
/* Look for user data */
|
|
return 0;
|
|
}
|
|
|
|
static char *clear_code(unsigned char code)
|
|
{
|
|
static char buffer[25];
|
|
|
|
if (code == 0x00 || (code & 0x80) == 0x80)
|
|
return "DTE Originated";
|
|
if (code == 0x01)
|
|
return "Number Busy";
|
|
if (code == 0x03)
|
|
return "Invalid Facility Requested";
|
|
if (code == 0x05)
|
|
return "Network Congestion";
|
|
if (code == 0x09)
|
|
return "Out Of Order";
|
|
if (code == 0x0B)
|
|
return "Access Barred";
|
|
if (code == 0x0D)
|
|
return "Not Obtainable";
|
|
if (code == 0x11)
|
|
return "Remote Procedure Error";
|
|
if (code == 0x13)
|
|
return "Local Procedure Error";
|
|
if (code == 0x15)
|
|
return "RPOA Out Of Order";
|
|
if (code == 0x19)
|
|
return "Reverse Charging Acceptance Not Subscribed";
|
|
if (code == 0x21)
|
|
return "Incompatible Destination";
|
|
if (code == 0x29)
|
|
return "Fast Select Acceptance Not Subscribed";
|
|
if (code == 0x39)
|
|
return "Destination Absent";
|
|
|
|
sprintf(buffer, "Unknown %02X", code);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
static char *clear_diag(unsigned char code)
|
|
{
|
|
static char buffer[25];
|
|
|
|
if (code == 0)
|
|
return "No additional information";
|
|
if (code == 1)
|
|
return "Invalid P(S)";
|
|
if (code == 2)
|
|
return "Invalid P(R)";
|
|
if (code == 16)
|
|
return "Packet type invalid";
|
|
if (code == 17)
|
|
return "Packet type invalid for state r1";
|
|
if (code == 18)
|
|
return "Packet type invalid for state r2";
|
|
if (code == 19)
|
|
return "Packet type invalid for state r3";
|
|
if (code == 20)
|
|
return "Packet type invalid for state p1";
|
|
if (code == 21)
|
|
return "Packet type invalid for state p2";
|
|
if (code == 22)
|
|
return "Packet type invalid for state p3";
|
|
if (code == 23)
|
|
return "Packet type invalid for state p4";
|
|
if (code == 24)
|
|
return "Packet type invalid for state p5";
|
|
if (code == 25)
|
|
return "Packet type invalid for state p6";
|
|
if (code == 26)
|
|
return "Packet type invalid for state p7";
|
|
if (code == 27)
|
|
return "Packet type invalid for state d1";
|
|
if (code == 28)
|
|
return "Packet type invalid for state d2";
|
|
if (code == 29)
|
|
return "Packet type invalid for state d3";
|
|
if (code == 32)
|
|
return "Packet not allowed";
|
|
if (code == 33)
|
|
return "Unidentifiable packet";
|
|
if (code == 34)
|
|
return "Call on one-way logical channel";
|
|
if (code == 35)
|
|
return "Invalid packet type on a PVC";
|
|
if (code == 36)
|
|
return "Packet on unassigned LC";
|
|
if (code == 37)
|
|
return "Reject not subscribed to";
|
|
if (code == 38)
|
|
return "Packet too short";
|
|
if (code == 39)
|
|
return "Packet too long";
|
|
if (code == 40)
|
|
return "Invalid general format identifier";
|
|
if (code == 41)
|
|
return "Restart/registration packet with nonzero bits";
|
|
if (code == 42)
|
|
return "Packet type not compatible with facility";
|
|
if (code == 43)
|
|
return "Unauthorised interrupt confirmation";
|
|
if (code == 44)
|
|
return "Unauthorised interrupt";
|
|
if (code == 45)
|
|
return "Unauthorised reject";
|
|
if (code == 48)
|
|
return "Time expired";
|
|
if (code == 49)
|
|
return "Time expired for incoming call";
|
|
if (code == 50)
|
|
return "Time expired for clear indication";
|
|
if (code == 51)
|
|
return "Time expired for reset indication";
|
|
if (code == 52)
|
|
return "Time expired for restart indication";
|
|
if (code == 53)
|
|
return "Time expired for call deflection";
|
|
if (code == 64)
|
|
return "Call set-up/clearing or registration pb.";
|
|
if (code == 65)
|
|
return "Facility/registration code not allowed";
|
|
if (code == 66)
|
|
return "Facility parameter not allowed";
|
|
if (code == 67)
|
|
return "Invalid called DTE address";
|
|
if (code == 68)
|
|
return "Invalid calling DTE address";
|
|
if (code == 69)
|
|
return "Invalid facility/registration length";
|
|
if (code == 70)
|
|
return "Incoming call barred";
|
|
if (code == 71)
|
|
return "No logical channel available";
|
|
if (code == 72)
|
|
return "Call collision";
|
|
if (code == 73)
|
|
return "Duplicate facility requested";
|
|
if (code == 74)
|
|
return "Non zero address length";
|
|
if (code == 75)
|
|
return "Non zero facility length";
|
|
if (code == 76)
|
|
return "Facility not provided when expected";
|
|
if (code == 77)
|
|
return "Invalid CCITT-specified DTE facility";
|
|
if (code == 78)
|
|
return "Max. nb of call redir/defl. exceeded";
|
|
if (code == 80)
|
|
return "Miscellaneous";
|
|
if (code == 81)
|
|
return "Improper cause code from DTE";
|
|
if (code == 82)
|
|
return "Not aligned octet";
|
|
if (code == 83)
|
|
return "Inconsistent Q bit setting";
|
|
if (code == 84)
|
|
return "NUI problem";
|
|
if (code == 112)
|
|
return "International problem";
|
|
if (code == 113)
|
|
return "Remote network problem";
|
|
if (code == 114)
|
|
return "International protocol problem";
|
|
if (code == 115)
|
|
return "International link out of order";
|
|
if (code == 116)
|
|
return "International link busy";
|
|
if (code == 117)
|
|
return "Transit network facility problem";
|
|
if (code == 118)
|
|
return "Remote network facility problem";
|
|
if (code == 119)
|
|
return "International routing problem";
|
|
if (code == 120)
|
|
return "Temporary routing problem";
|
|
if (code == 121)
|
|
return "Unknown called DNIC";
|
|
if (code == 122)
|
|
return "Maintenance action";
|
|
if (code == 144)
|
|
return "Timer expired or retransmission count surpassed";
|
|
if (code == 145)
|
|
return "Timer expired or retransmission count surpassed for INTERRUPT";
|
|
if (code == 146)
|
|
return "Timer expired or retransmission count surpassed for DATA "
|
|
"packet transmission";
|
|
if (code == 147)
|
|
return "Timer expired or retransmission count surpassed for REJECT";
|
|
if (code == 160)
|
|
return "DTE-specific signals";
|
|
if (code == 161)
|
|
return "DTE operational";
|
|
if (code == 162)
|
|
return "DTE not operational";
|
|
if (code == 163)
|
|
return "DTE resource constraint";
|
|
if (code == 164)
|
|
return "Fast select not subscribed";
|
|
if (code == 165)
|
|
return "Invalid partially full DATA packet";
|
|
if (code == 166)
|
|
return "D-bit procedure not supported";
|
|
if (code == 167)
|
|
return "Registration/Cancellation confirmed";
|
|
if (code == 224)
|
|
return "OSI network service problem";
|
|
if (code == 225)
|
|
return "Disconnection (transient condition)";
|
|
if (code == 226)
|
|
return "Disconnection (permanent condition)";
|
|
if (code == 227)
|
|
return "Connection rejection - reason unspecified (transient "
|
|
"condition)";
|
|
if (code == 228)
|
|
return "Connection rejection - reason unspecified (permanent "
|
|
"condition)";
|
|
if (code == 229)
|
|
return "Connection rejection - quality of service not available "
|
|
"transient condition)";
|
|
if (code == 230)
|
|
return "Connection rejection - quality of service not available "
|
|
"permanent condition)";
|
|
if (code == 231)
|
|
return "Connection rejection - NSAP unreachable (transient condition)";
|
|
if (code == 232)
|
|
return "Connection rejection - NSAP unreachable (permanent condition)";
|
|
if (code == 233)
|
|
return "reset - reason unspecified";
|
|
if (code == 234)
|
|
return "reset - congestion";
|
|
if (code == 235)
|
|
return "Connection rejection - NSAP address unknown (permanent "
|
|
"condition)";
|
|
if (code == 240)
|
|
return "Higher layer initiated";
|
|
if (code == 241)
|
|
return "Disconnection - normal";
|
|
if (code == 242)
|
|
return "Disconnection - abnormal";
|
|
if (code == 243)
|
|
return "Disconnection - incompatible information in user data";
|
|
if (code == 244)
|
|
return "Connection rejection - reason unspecified (transient "
|
|
"condition)";
|
|
if (code == 245)
|
|
return "Connection rejection - reason unspecified (permanent "
|
|
"condition)";
|
|
if (code == 246)
|
|
return "Connection rejection - quality of service not available "
|
|
"(transient condition)";
|
|
if (code == 247)
|
|
return "Connection rejection - quality of service not available "
|
|
"(permanent condition)";
|
|
if (code == 248)
|
|
return "Connection rejection - incompatible information in user data";
|
|
if (code == 249)
|
|
return "Connection rejection - unrecognizable protocol indentifier "
|
|
"in user data";
|
|
if (code == 250)
|
|
return "Reset - user resynchronization";
|
|
|
|
sprintf(buffer, "Unknown %d", code);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
void decode_pkt (unsigned char *data,int len,
|
|
unsigned char status, unsigned int timestamp,
|
|
int protocol)
|
|
{
|
|
int inf_frame=0;
|
|
int trace_started=0;
|
|
int dlci;
|
|
|
|
if (match_trace_criteria(data,len,&dlci) != 0)
|
|
return;
|
|
|
|
if (!TRACE_EBCDIC && !TRACE_ASCII && !TRACE_HEX){
|
|
TRACE_HEX=1;
|
|
}
|
|
|
|
if (protocol){
|
|
if (TRACE_PROTOCOL & FRAME){
|
|
|
|
trace_banner(len,status,timestamp,&trace_started);
|
|
|
|
printf("\tFR : ");
|
|
printf("DLCI=%i ", dlci);
|
|
printf("C/R=%i ", (data[0]&0x2)>>1);
|
|
printf("EA=%i ", data[0]&0x1);
|
|
printf("FECN=%i ", (data[1]&0x8)>>3);
|
|
printf("BECN=%i ", (data[1]&0x4)>>2);
|
|
printf("DE=%i ", (data[1]&0x2)>>1);
|
|
printf("EA=%i ", data[1]&0x1);
|
|
printf("\n");
|
|
|
|
if (!dlci || dlci==1023){
|
|
printf("\n");
|
|
return;
|
|
}
|
|
}
|
|
data+=2;
|
|
len-=2;
|
|
|
|
if (!dlci || dlci==1023){
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (len<2){
|
|
return;
|
|
}
|
|
|
|
if (TRACE_PROTOCOL & LAPB){
|
|
|
|
trace_banner(len,status,timestamp,&trace_started);
|
|
|
|
inf_frame=0;
|
|
printf("\tLAPB : %02i | ",data[0]);
|
|
|
|
if (!(data[1]&0x01)){
|
|
if (len >= 5){
|
|
printf("INF Ns=%1i Nr=%1i P=%1i : <data, len=%i >",
|
|
(data[1]>>1)&0x07,
|
|
data[1]>>5,
|
|
(data[1]>>4)&0x01,(len-2));
|
|
inf_frame=1;
|
|
}else{
|
|
printf("INF Ns=%1i Nr=%1i P=%1i ",
|
|
(data[1]>>1)&0x07,
|
|
data[1]>>5,
|
|
(data[1]>>4)&0x01);
|
|
}
|
|
goto end_lapb_decode;
|
|
}
|
|
|
|
switch ((data[1]&0x0F)){
|
|
|
|
case 0x01:
|
|
printf("RR Pr=%1i P=%1i",
|
|
(data[1]>>5),
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
|
|
case 0x05:
|
|
printf("RNR Pr=%1i P=%1i",
|
|
(data[1]>>5),
|
|
(data[1]>>4)&0x01);
|
|
|
|
break;
|
|
|
|
case 0x09:
|
|
printf("REJ Pr=%1i P=%1i",
|
|
(data[1]>>5),
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
|
|
default:
|
|
|
|
switch (data[1]&0xEF){
|
|
|
|
case 0x2F:
|
|
printf("SBM P=%1i",
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
case 0x0F:
|
|
printf("DM F=%1i",
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
|
|
case 0x43:
|
|
printf("DSC P=%1i",
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
case 0x63:
|
|
printf("UA F=%1i",
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
|
|
case 0x87:
|
|
printf("FMR F=%1i",
|
|
(data[1]>>4)&0x01);
|
|
break;
|
|
|
|
default:
|
|
printf("Unknown lapb pkt : 0x%02X ", data[1]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
end_lapb_decode:
|
|
printf("\n");
|
|
|
|
if (!inf_frame){
|
|
return;
|
|
}
|
|
|
|
}else{
|
|
/* Do not pass non information frames to X25 */
|
|
if ((data[1]&0x01)){
|
|
return;
|
|
}
|
|
}
|
|
|
|
data+=2;
|
|
len-=2;
|
|
|
|
if (len<3){
|
|
return;
|
|
}
|
|
|
|
|
|
if (TRACE_PROTOCOL & X25){
|
|
|
|
unsigned int lcn = ((data[0]&0x0F)<<8)|(data[1]&0xFF);
|
|
unsigned char mod = (data[0]>>4)&0x03;
|
|
unsigned char pkt_type;
|
|
unsigned char pr,ps,mbit;
|
|
|
|
inf_frame=0;
|
|
if (TRACE_X25_LCN){
|
|
if (lcn != 0 && TRACE_X25_LCN != lcn){
|
|
return;
|
|
}
|
|
}
|
|
|
|
pkt_type=data[2];
|
|
|
|
if (!(pkt_type&0x01)){
|
|
if (!(TRACE_X25_OPT & DATA)){
|
|
return;
|
|
}
|
|
}else{
|
|
if (!(TRACE_X25_OPT & PROT)){
|
|
return;
|
|
}
|
|
}
|
|
|
|
trace_banner(len,status,timestamp,&trace_started);
|
|
|
|
printf("\tX25 : LCN=%i Q=%i D=%i Modulo=%i : ",
|
|
lcn,
|
|
data[0]&0x80,
|
|
data[0]&0x40,
|
|
data[0]&0x10 ? 8 : 128);
|
|
|
|
if (!(pkt_type&0x01)){
|
|
|
|
if (mod==X25_MOD8){
|
|
pr=data[2]>>5;
|
|
ps=(data[2]>>1)&0x07;
|
|
mbit=(data[2]&0x10)>>4;
|
|
}else{
|
|
ps=data[2]>>1;
|
|
pr=data[3]>>1;
|
|
mbit=data[3]&0x01;
|
|
}
|
|
|
|
printf("DATA Pr=%02i Ps=%02i M=%i",
|
|
pr,ps,mbit);
|
|
inf_frame=1;
|
|
goto end_x25_decode;
|
|
}else{
|
|
if (mod==X25_MOD8){
|
|
pr=data[2]>>5;
|
|
}else{
|
|
pr=data[3]>>1;
|
|
}
|
|
}
|
|
|
|
switch(pkt_type&0x1F){
|
|
|
|
case 0x01:
|
|
printf("\n\t ");
|
|
printf("RR Pr=%02i",pr);
|
|
break;
|
|
|
|
case 0x05:
|
|
printf("\n\t ");
|
|
printf("RNR Pr=%02i",pr);
|
|
break;
|
|
|
|
case 0x09:
|
|
printf("\n\t ");
|
|
printf("REJ Pr=%02i",pr);
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("\n\t * ");
|
|
|
|
switch(pkt_type){
|
|
|
|
case 0x0B:
|
|
printf("CALL REQUEST :\n\t ");
|
|
x25_call_request_decode(data,len);
|
|
break;
|
|
|
|
case 0x0F:
|
|
printf("CALL ACCEPT ");
|
|
break;
|
|
|
|
case 0x13:
|
|
printf("CLEAR REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x17:
|
|
printf("CLEAR CONFIRM :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x23:
|
|
printf("INTERRUPT :\n\t ");
|
|
printf("Data=(0x%02X)",data[3]);
|
|
break;
|
|
|
|
case 0x27:
|
|
printf("INTERRUPT CONFIRM");
|
|
break;
|
|
|
|
case 0x1B:
|
|
printf("RESET REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x1F:
|
|
printf("RESET CONFIRM");
|
|
break;
|
|
|
|
case 0xFB:
|
|
printf("RESTART REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0xFF:
|
|
printf("RESTART CONFIRM");
|
|
break;
|
|
|
|
case 0xF1:
|
|
printf("\nDIAGNOSTIC");
|
|
break;
|
|
|
|
default:
|
|
printf("\nUnknown x25 cmd 0x%2X",data[2]);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
end_x25_decode:
|
|
|
|
if (inf_frame){
|
|
int i;
|
|
char ch;
|
|
char *specials = "\b\f\n\r\t";
|
|
char *escapes = "bfnrt";
|
|
char *cp;
|
|
|
|
printf("\n");
|
|
|
|
if (TRACE_HEX){
|
|
printf("\n\thex : ");
|
|
for (i=3;i<len;i++){
|
|
printf("%02X ",data[i]);
|
|
|
|
if (((i-2) % 20) == 0){
|
|
printf("\n\t ");
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
if (TRACE_ASCII){ /* we're dumping ASCII */
|
|
printf("\n\tascii: ");
|
|
for (i=3;i<len;i++){
|
|
|
|
ch = (isprint (data[i]) || data[i] == ' ') ? data[i] : '.';
|
|
|
|
if ((isprint(data[i]) || data[i] == ' '))
|
|
(void) printf("%c", ch);
|
|
else if (data[i] && (cp = strchr(specials, data[i])))
|
|
(void) printf("\\%c", escapes[cp - specials]);
|
|
else
|
|
(void) printf("%02X", ch);
|
|
|
|
//if (((i-2) % 25) == 0){
|
|
// printf("\n\t ");
|
|
//}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
if (TRACE_EBCDIC){ /* we're dumping EBCDIC (blecch!) */
|
|
|
|
printf("\n\tebcdic:");
|
|
for (i=3;i<len;i++){
|
|
|
|
ch = (data[i] >= 0x40) ? ebcdic[data[i] - 0x40] : '.';
|
|
|
|
if ((ch != '.' || data[i] == ebcdic['.']))
|
|
(void) printf("%c", ch);
|
|
else if (data[i] && (cp = strchr(specials, data[i])))
|
|
(void) printf("\\%c", escapes[cp - specials]);
|
|
else
|
|
(void) printf("%02X", data[i]);
|
|
|
|
//if (((i-2) % 25) == 0){
|
|
// printf("\n\t ");
|
|
//}
|
|
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
}else{ //end of inf frame
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void decode_x25(unsigned char *data)
|
|
{
|
|
unsigned int lcn = ((data[0]&0x0F)<<8)|(data[1]&0xFF);
|
|
unsigned char mod = (data[0]>>4)&0x03;
|
|
unsigned char pkt_type;
|
|
unsigned char pr,ps,mbit;
|
|
unsigned char inf_frame=0;
|
|
|
|
if (TRACE_X25_LCN){
|
|
if (lcn != 0 && TRACE_X25_LCN != lcn){
|
|
return;
|
|
}
|
|
}
|
|
|
|
pkt_type=data[2];
|
|
|
|
if (!(pkt_type&0x01)){
|
|
if (!(TRACE_X25_OPT & DATA)){
|
|
return;
|
|
}
|
|
}else{
|
|
if (!(TRACE_X25_OPT & PROT)){
|
|
return;
|
|
}
|
|
}
|
|
|
|
trace_banner(len,status,timestamp,&trace_started);
|
|
|
|
printf("\tX25 : LCN=%i Q=%i D=%i Modulo=%i : ",
|
|
lcn,
|
|
data[0]&0x80,
|
|
data[0]&0x40,
|
|
data[0]&0x10 ? 8 : 128);
|
|
|
|
if (!(pkt_type&0x01)){
|
|
|
|
if (mod==X25_MOD8){
|
|
pr=data[2]>>5;
|
|
ps=(data[2]>>1)&0x07;
|
|
mbit=(data[2]&0x10)>>4;
|
|
}else{
|
|
ps=data[2]>>1;
|
|
pr=data[3]>>1;
|
|
mbit=data[3]&0x01;
|
|
}
|
|
|
|
printf("DATA Pr=%02i Ps=%02i M=%i",
|
|
pr,ps,mbit);
|
|
inf_frame=1;
|
|
goto end_x25_decode;
|
|
}else{
|
|
if (mod==X25_MOD8){
|
|
pr=data[2]>>5;
|
|
}else{
|
|
pr=data[3]>>1;
|
|
}
|
|
}
|
|
|
|
switch(pkt_type&0x1F){
|
|
|
|
case 0x01:
|
|
printf("\n\t ");
|
|
printf("RR Pr=%02i",pr);
|
|
break;
|
|
|
|
case 0x05:
|
|
printf("\n\t ");
|
|
printf("RNR Pr=%02i",pr);
|
|
break;
|
|
|
|
case 0x09:
|
|
printf("\n\t ");
|
|
printf("REJ Pr=%02i",pr);
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("\n\t * ");
|
|
|
|
switch(pkt_type){
|
|
|
|
case 0x0B:
|
|
printf("CALL REQUEST :\n\t ");
|
|
x25_call_request_decode(data,len);
|
|
break;
|
|
|
|
case 0x0F:
|
|
printf("CALL ACCEPT ");
|
|
break;
|
|
|
|
case 0x13:
|
|
printf("CLEAR REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x17:
|
|
printf("CLEAR CONFIRM :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x23:
|
|
printf("INTERRUPT :\n\t ");
|
|
printf("Data=(0x%02X)",data[3]);
|
|
break;
|
|
|
|
case 0x27:
|
|
printf("INTERRUPT CONFIRM");
|
|
break;
|
|
|
|
case 0x1B:
|
|
printf("RESET REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0x1F:
|
|
printf("RESET CONFIRM");
|
|
break;
|
|
|
|
case 0xFB:
|
|
printf("RESTART REQUEST :\n\t ");
|
|
printf("Code=(0x%02X)%s : Diag=(0x%02X)%s",
|
|
data[3],clear_code(data[3]),
|
|
data[4],clear_diag(data[4]));
|
|
break;
|
|
|
|
case 0xFF:
|
|
printf("RESTART CONFIRM");
|
|
break;
|
|
|
|
case 0xF1:
|
|
printf("\nDIAGNOSTIC");
|
|
break;
|
|
|
|
default:
|
|
printf("\nUnknown x25 cmd 0x%2X",data[2]);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
end_x25_decode:
|
|
|
|
if (inf_frame){
|
|
int i;
|
|
char ch;
|
|
char *specials = "\b\f\n\r\t";
|
|
char *escapes = "bfnrt";
|
|
char *cp;
|
|
|
|
printf("\n");
|
|
|
|
if (TRACE_HEX){
|
|
printf("\n\thex : ");
|
|
for (i=3;i<len;i++){
|
|
printf("%02X ",data[i]);
|
|
|
|
if (((i-2) % 20) == 0){
|
|
printf("\n\t ");
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
if (TRACE_ASCII){ /* we're dumping ASCII */
|
|
printf("\n\tascii: ");
|
|
for (i=3;i<len;i++){
|
|
|
|
ch = (isprint (data[i]) || data[i] == ' ') ? data[i] : '.';
|
|
|
|
if ((isprint(data[i]) || data[i] == ' '))
|
|
(void) printf("%c", ch);
|
|
else if (data[i] && (cp = strchr(specials, data[i])))
|
|
(void) printf("\\%c", escapes[cp - specials]);
|
|
else
|
|
(void) printf("%02X", ch);
|
|
|
|
//if (((i-2) % 25) == 0){
|
|
// printf("\n\t ");
|
|
//}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
if (TRACE_EBCDIC){ /* we're dumping EBCDIC (blecch!) */
|
|
|
|
printf("\n\tebcdic:");
|
|
for (i=3;i<len;i++){
|
|
|
|
ch = (data[i] >= 0x40) ? ebcdic[data[i] - 0x40] : '.';
|
|
|
|
if ((ch != '.' || data[i] == ebcdic['.']))
|
|
(void) printf("%c", ch);
|
|
else if (data[i] && (cp = strchr(specials, data[i])))
|
|
(void) printf("\\%c", escapes[cp - specials]);
|
|
else
|
|
(void) printf("%02X", data[i]);
|
|
|
|
//if (((i-2) % 25) == 0){
|
|
// printf("\n\t ");
|
|
//}
|
|
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
}else{ //end of inf frame
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void print_pcap_file_header (wp_trace_output_iface_t *trace_iface)
|
|
{
|
|
struct pcap_hdr fh;
|
|
|
|
fh.magic = PCAP_MAGIC;
|
|
fh.version_major = 2;
|
|
fh.version_minor = 4;
|
|
fh.thiszone = 0;
|
|
fh.sigfigs = 0;
|
|
fh.snaplen = 102400;
|
|
fh.network = trace_iface->link_type;
|
|
|
|
fwrite(&fh, sizeof(fh), 1, trace_iface->output_file);
|
|
}
|
|
|
|
static void print_pcap_record_header(wp_trace_output_iface_t *trace_iface)
|
|
{
|
|
struct pcaprec_hdr ph;
|
|
|
|
/* Write PCap header */
|
|
ph.ts_sec = trace_iface->pkts_written;
|
|
ph.ts_usec = trace_iface->pkts_written;
|
|
ph.incl_len = trace_iface->len;
|
|
ph.orig_len = trace_iface->len;
|
|
|
|
fwrite(&ph, sizeof(ph), 1, trace_iface->output_file);
|
|
}
|
|
|
|
void wp_trace_output(wp_trace_output_iface_t *trace_iface)
|
|
{
|
|
int num_chars;
|
|
int j;
|
|
|
|
switch (trace_iface->type){
|
|
|
|
|
|
case WP_OUT_TRACE_INTERP:
|
|
|
|
decode_pkt(trace_iface->data,
|
|
trace_iface->len,
|
|
trace_iface->status,
|
|
trace_iface->timestamp,
|
|
0);
|
|
|
|
break;
|
|
|
|
case WP_OUT_TRACE_PCAP:
|
|
|
|
trace_iface->output_file = pcap_output_file;
|
|
if (trace_iface->output_file == NULL){
|
|
printf("Error: No output binary file specified!\n");
|
|
return;
|
|
}
|
|
|
|
if (trace_iface->init==0){
|
|
|
|
if (pcap_prot){
|
|
trace_iface->link_type=pcap_prot;
|
|
}
|
|
|
|
print_pcap_file_header(trace_iface);
|
|
printf("Staring PCAP File Trace in: %s\n\n",
|
|
pcap_output_file_name);
|
|
trace_iface->init=1;
|
|
}
|
|
|
|
print_pcap_record_header(trace_iface);
|
|
|
|
fwrite(&trace_iface->data[0], trace_iface->len, 1, trace_iface->output_file);
|
|
|
|
printf("\rTotal Captured=%-5u (Len=%i)",trace_iface->pkts_written+1,trace_iface->len);
|
|
|
|
break;
|
|
|
|
case WP_OUT_TRACE_RAW:
|
|
default:
|
|
|
|
if (trace_iface->status & WP_TRACE_OUTGOING){
|
|
printf("\nOUTGOING\t");
|
|
}else{
|
|
printf("\nINCOMING\t");
|
|
}
|
|
|
|
printf("Len=%-5u\tTimestamp=%-5u\t",
|
|
trace_iface->len,
|
|
trace_iface->timestamp);
|
|
|
|
trace_iface->status&=(~WP_TRACE_OUTGOING);
|
|
|
|
if (trace_iface->status){
|
|
printf("Receive error - ");
|
|
|
|
if(trace_iface->status & WP_TRACE_ABORT){
|
|
printf("Abort");
|
|
}else{
|
|
printf((trace_iface->status & WP_TRACE_CRC) ? "Bad CRC" : "Overrun");
|
|
}
|
|
}
|
|
|
|
if (trace_iface->len == 0){
|
|
printf("the frame data is not available" );
|
|
return;
|
|
}
|
|
|
|
if (!trace_iface->trace_all_data){
|
|
num_chars = ((trace_iface->len <= DEFAULT_TRACE_LEN)?
|
|
trace_iface->len:DEFAULT_TRACE_LEN);
|
|
}else{
|
|
num_chars = trace_iface->len;
|
|
}
|
|
|
|
printf("\n\t\t");
|
|
for( j=0; j<num_chars; j++ ) {
|
|
if (j!=0 && !(j%20)){
|
|
printf("\n\t\t");
|
|
}
|
|
printf("%02X ", trace_iface->data[j]);
|
|
}
|
|
|
|
if (num_chars < trace_iface->len){
|
|
printf("..");
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
break;
|
|
}
|
|
|
|
trace_iface->pkts_written++;
|
|
trace_iface->status=0;
|
|
}
|
|
|
|
|
|
|