/* * Copyright 1996 Jonathan Naylor G4KLX * * Added ROSE new facilities : Jean-Paul ROUBELAT 04-1998 * Added ROSE multi-digi : Jean-Paul ROUBELAT 05-1998 * Added ROSE PID transport : Jean-Paul ROUBELAT 07-1998 */ #include #include #include "listen.h" #define PID_SEGMENT 0x08 #define PID_ARP 0xCD #define PID_NETROM 0xCF #define PID_IP 0xCC #define PID_X25 0x01 #define PID_TEXNET 0xC3 #define PID_FLEXNET 0xCE #define PID_NO_L3 0xF0 #define ROSE_ADDR_LEN 5 #define CALL_REQUEST 0x0B #define CALL_ACCEPTED 0x0F #define CLEAR_REQUEST 0x13 #define CLEAR_CONFIRMATION 0x17 #define INTERRUPT 0x23 #define INTERRUPT_CONFIRMATION 0x27 #define RESET_REQUEST 0x1B #define RESET_CONFIRMATION 0x1F #define RESTART_REQUEST 0xFB #define RESTART_CONFIRMATION 0xFF #define REGISTRATION_REQUEST 0xF3 #define REGISTRATION_CONFIRMATION 0xF7 #define DIAGNOSTIC 0xF1 #define RR 0x01 #define RNR 0x05 #define REJ 0x09 #define DATA 0x00 #define QBIT 0x80 #define DBIT 0x40 #define MBIT 0x10 #define AX25_HBIT 0x80 static char *dump_x25_addr(unsigned char *); static char *clear_code(unsigned char); static char *reset_code(unsigned char); static char *restart_code(unsigned char); static void facility(unsigned char *, int len); void rose_dump(unsigned char *data, int length, int hexdump) { unsigned int len, hlen; unsigned int lci = ((unsigned) (data[0] & 0x0F) << 8) + data[1]; lprintf(T_ROSEHDR, "X.25: LCI %3.3X : ", lci); switch (data[2]) { case CALL_REQUEST: len = 4; hlen = (((data[3] >> 4) & 0x0F) + 1) / 2; hlen += (((data[3] >> 0) & 0x0F) + 1) / 2; len += hlen; data += len; length -= len; lprintf(T_ROSEHDR, "CALL REQUEST - "); if (length) { unsigned int flen = data[0] + 1; facility(data, length); length -= flen; data += flen; if (length > 0) data_dump(data, length, 1); } else { lprintf(T_ROSEHDR, "\n"); } return; case CALL_ACCEPTED: lprintf(T_ROSEHDR, "CALL ACCEPTED\n"); return; case CLEAR_REQUEST: lprintf(T_ROSEHDR, "CLEAR REQUEST - Cause %s - Diag %d\n", clear_code(data[3]), data[4]); if (length > 6) { facility(data + 6, length - 6); } return; case CLEAR_CONFIRMATION: lprintf(T_ROSEHDR, "CLEAR CONFIRMATION\n"); return; case DIAGNOSTIC: lprintf(T_ROSEHDR, "DIAGNOSTIC - Diag %d\n", data[3]); return; case INTERRUPT: lprintf(T_ROSEHDR, "INTERRUPT\n"); data_dump(data + 3, length - 3, hexdump); return; case INTERRUPT_CONFIRMATION: lprintf(T_ROSEHDR, "INTERRUPT CONFIRMATION\n"); return; case RESET_REQUEST: lprintf(T_ROSEHDR, "RESET REQUEST - Cause %s - Diag %d\n", reset_code(data[3]), data[4]); return; case RESET_CONFIRMATION: lprintf(T_ROSEHDR, "RESET CONFIRMATION\n"); return; case RESTART_REQUEST: lprintf(T_ROSEHDR, "RESTART REQUEST - Cause %s - Diag %d\n", restart_code(data[3]), data[4]); return; case RESTART_CONFIRMATION: lprintf(T_ROSEHDR, "RESTART CONFIRMATION\n"); return; case REGISTRATION_REQUEST: lprintf(T_ROSEHDR, "REGISTRATION REQUEST\n"); return; case REGISTRATION_CONFIRMATION: lprintf(T_ROSEHDR, "REGISTRATION CONFIRMATION\n"); return; } if ((data[2] & 0x01) == DATA) { lprintf(T_ROSEHDR, "DATA R%d S%d %s%s%s", (data[2] >> 5) & 0x07, (data[2] >> 1) & 0x07, (data[0] & QBIT) ? "Q" : "", (data[0] & DBIT) ? "D" : "", (data[2] & MBIT) ? "M" : ""); if ((length >= 5) && (data[0] & QBIT) && (data[3] == 0x7f)) { /* pid transport */ int pid = data[4]; data += 5; length -= 5; switch (pid) { case PID_SEGMENT: lprintf(T_ROSEHDR," len %d\n", length - 5); data_dump(data, length, hexdump); break; case PID_ARP: lprintf(T_ROSEHDR," pid=ARP len %d\n", length - 5); arp_dump(data, length); break; case PID_NETROM: lprintf(T_ROSEHDR," pid=NET/ROM len %d\n", length - 5); netrom_dump(data, length, hexdump, 0); break; case PID_IP: lprintf(T_ROSEHDR," pid=IP len %d\n", length - 5); ip_dump(data, length, hexdump); break; case PID_X25: lprintf(T_ROSEHDR, " pid=X.25 len %d\n", length - 5); rose_dump(data, length, hexdump); break; case PID_TEXNET: lprintf(T_ROSEHDR, " pid=TEXNET len %d\n", length - 5); data_dump(data, length, hexdump); break; case PID_FLEXNET: lprintf(T_ROSEHDR, " pid=FLEXNET len %d\n", length - 5); flexnet_dump(data, length, hexdump); break; case PID_NO_L3: lprintf(T_ROSEHDR, " pid=Text len %d\n", length - 5); data_dump(data, length, hexdump); break; default: lprintf(T_ROSEHDR, " pid=0x%x len %d\n", pid, length - 5); data_dump(data, length, hexdump); break; } } else { lprintf(T_ROSEHDR, " len %d\n", length - 3); data_dump(data + 3, length - 3, hexdump); } return; } switch (data[2] & 0x1F) { case RR: lprintf(T_ROSEHDR, "RR R%d\n", (data[2] >> 5) & 0x07); return; case RNR: lprintf(T_ROSEHDR, "RNR R%d\n", (data[2] >> 5) & 0x07); return; case REJ: lprintf(T_ROSEHDR, "REJ R%d\n", (data[2] >> 5) & 0x07); return; } lprintf(T_ROSEHDR, "UNKNOWN\n"); data_dump(data, length, 1); } 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 == 0x09) return "Out Of Order"; if (code == 0x11) return "Remote Procedure Error"; 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"; if (code == 0x03) return "Invalid Facility Requested"; if (code == 0x0B) return "Access Barred"; if (code == 0x13) return "Local Procedure Error"; if (code == 0x05) return "Network Congestion"; if (code == 0x0D) return "Not Obtainable"; if (code == 0x15) return "RPOA Out Of Order"; sprintf(buffer, "Unknown %02X", code); return buffer; } static char *reset_code(unsigned char code) { static char buffer[25]; if (code == 0x00 || (code & 0x80) == 0x80) return "DTE Originated"; if (code == 0x03) return "Remote Procedure Error"; if (code == 0x11) return "Incompatible Destination"; if (code == 0x05) return "Local Procedure Error"; if (code == 0x07) return "Network Congestion"; sprintf(buffer, "Unknown %02X", code); return buffer; } static char *restart_code(unsigned char code) { static char buffer[25]; if (code == 0x00 || (code & 0x80) == 0x80) return "DTE Originated"; if (code == 0x01) return "Local Procedure Error"; if (code == 0x03) return "Network Congestion"; if (code == 0x07) return "Network Operational"; sprintf(buffer, "Unknown %02X", code); return buffer; } static char *dump_x25_addr(unsigned char *data) { static char buffer[25]; sprintf(buffer, "%02X%02X,%02X%02X%02X", data[0], data[1], data[2], data[3], data[4]); return buffer; } static char *dump_ax25_call(unsigned char *data, int l_data) { static char buffer[25]; char *ptr = buffer; int ssid; while (l_data-- > 1) { *ptr = *data++ >> 1; if (*ptr != ' ') ++ptr; } *ptr++ = '-'; ssid = (*data & 0x1F) >> 1; if (ssid >= 10) { *ptr++ = '1'; ssid -= 10; } *ptr++ = ssid + '0'; *ptr = 0; return buffer; } static void facility(unsigned char *data, int lgtot) { int lgfac, l, lg, fct, lgdigi, lgaddcall; int lgad, lgadind, digi_fac; char digis[80], digid[80]; char indorig[10], inddest[10]; char addstorig[20], addstdest[20]; unsigned char *d, *factot; char buf[512]; char *result = buf; factot = data; lgfac = *data++; lg = lgfac; digi_fac = 0; digid[0] = digis[0] = '\0'; indorig[0] = inddest[0] = '\0'; while (lg > 0) { fct = *data++; lg--; switch (fct) { case 0: /* Marker=0 National Fac ou Marker=15 CCITT */ data++; lg--; break; case 0x3F: /* Used if call request via L2 digi instead of L3 */ lprintf(T_ROSEHDR, "Facility 3F%2.2X\n", *data++); lg--; break; case 0x7F: /* Random number to avoid loops */ lprintf(T_ROSEHDR, "NbAlea: %2.2X%2.2X\n", *data, *(data + 1)); data += 2; lg -= 2; break; case 0xE9: /* Destination digi (for compatibility) */ lgdigi = *data++; if (!digi_fac) strcpy(digid, dump_ax25_call(data, lgdigi)); data += lgdigi; lg -= 1 + lgdigi; break; case 0xEB: /* Origin digi (for compatibility) */ lgdigi = *data++; if (!digi_fac) strcpy(digis, dump_ax25_call(data, lgdigi)); data += lgdigi; lg -= 1 + lgdigi; break; case 0xED: /* Out of order : callsign */ lgaddcall = *data++; lprintf(T_ROSEHDR, "at %s", dump_ax25_call(data, lgaddcall)); data += lgaddcall; lg -= 1 + lgaddcall; break; case 0xEE: /* Out of order : address */ lgaddcall = *data++; ++data; /* Don't know... */ lprintf(T_ROSEHDR, " @%s\n", dump_x25_addr(data)); /* data_dump(data, lgaddcall, 1); */ data += lgaddcall; lg -= 1 + lgaddcall; break; case 0xEF: lgaddcall = *data++; for (d = data, l = 0; l < lgaddcall; l += 7, d += 7) { if (l > (6 * 7)) { /* 6 digis maximum */ break; } if (d[6] & AX25_HBIT) { strcat(digis, dump_ax25_call(d, 7)); strcat(digis, " "); } else { strcat(digid, dump_ax25_call(d, 7)); strcat(digid, " "); } } data += lgaddcall; lg -= 1 + lgaddcall; digi_fac = 1; break; case 0xC9: /* Address and callsign of the remote node */ case 0xCB: /* Address and callsign of the local node */ lgaddcall = *data++; data++; data += 3; lgad = *data++; lg -= 6; if (fct == 0xCB) strcpy(addstorig, dump_x25_addr(data)); else strcpy(addstdest, dump_x25_addr(data)); data += (lgad + 1) / 2; lg -= (lgad + 1) / 2; lgadind = lgaddcall - (lgad + 1) / 2 - 5; if (fct == 0xCB) { strncpy(indorig, (char *)data, lgadind); indorig[lgadind] = '\0'; } else { strncpy(inddest, (char *)data, lgadind); inddest[lgadind] = '\0'; } data += lgadind; lg -= lgadind; break; default: lprintf(T_ROSEHDR, "Unknown Facility Type %2.2X\n", fct); data_dump(factot, lgtot, 1); lg = 0; break; } result += strlen(result); } if (*indorig && *inddest) { /* Build the displayed string */ lprintf(T_ROSEHDR, "fm %-9s @%s", indorig, addstorig); if (*digis) lprintf(T_ROSEHDR, " via %s", digis); lprintf(T_ROSEHDR, "\n"); lprintf(T_ROSEHDR, "to %-9s @%s", inddest, addstdest); if (*digid) lprintf(T_ROSEHDR, " via %s", digid); lprintf(T_ROSEHDR, "\n"); } }