summaryrefslogtreecommitdiffstats
path: root/listen/ax25dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'listen/ax25dump.c')
-rw-r--r--listen/ax25dump.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/listen/ax25dump.c b/listen/ax25dump.c
new file mode 100644
index 0000000..34213f9
--- /dev/null
+++ b/listen/ax25dump.c
@@ -0,0 +1,362 @@
+/* @(#) $Header: ax25dump.c,v 1.5 91/02/24 20:16:33 deyke Exp $ */
+
+/* AX25 header tracing
+ * Copyright 1991 Phil Karn, KA9Q
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "listen.h"
+
+#define LAPB_UNKNOWN 0
+#define LAPB_COMMAND 1
+#define LAPB_RESPONSE 2
+
+#define SEG_FIRST 0x80
+#define SEG_REM 0x7F
+
+#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 I 0x00
+#define S 0x01
+#define RR 0x01
+#define RNR 0x05
+#define REJ 0x09
+#define U 0x03
+#define SABM 0x2F
+#define SABME 0x6F
+#define DISC 0x43
+#define DM 0x0F
+#define UA 0x63
+#define FRMR 0x87
+#define UI 0x03
+#define PF 0x10
+#define EPF 0x01
+
+#define MMASK 7
+
+#define HDLCAEB 0x01
+#define SSID 0x1E
+#define REPEATED 0x80
+#define C 0x80
+#define SSSID_SPARE 0x40
+#define ESSID_SPARE 0x20
+
+#define ALEN 6
+#define AXLEN 7
+
+#define W 1
+#define X 2
+#define Y 4
+#define Z 8
+
+static int ftype(unsigned char *, int *, int *, int *, int *, int);
+static char *decode_type(int);
+
+#define NDAMA_STRING ""
+#define DAMA_STRING " [DAMA]"
+
+
+/* FlexNet header compression display by Thomas Sailer sailer@ife.ee.ethz.ch */
+
+/* Dump an AX.25 packet header */
+void ax25_dump(unsigned char *data, int length, int hexdump)
+{
+ char tmp[15];
+ int ctlen, nr, ns, pf, pid, seg, type, end, cmdrsp, extseq;
+ char *dama;
+
+ /* check for FlexNet compressed header first; FlexNet header compressed packets are at least 8 bytes long */
+ if (length < 8) {
+ /* Something wrong with the header */
+ lprintf(T_ERROR, "AX25: bad header!\n");
+ return;
+ }
+ if (data[1] & HDLCAEB) {
+ /* this is a FlexNet compressed header */
+ lprintf(T_PROTOCOL, "AX25: ");
+ tmp[6] = tmp[7] = extseq = 0;
+ tmp[0] = ' ' + (data[2] >> 2);
+ tmp[1] = ' ' + ((data[2] << 4) & 0x30) + (data[3] >> 4);
+ tmp[2] = ' ' + ((data[3] << 2) & 0x3c) + (data[4] >> 6);
+ tmp[3] = ' ' + (data[4] & 0x3f);
+ tmp[4] = ' ' + (data[5] >> 2);
+ tmp[5] = ' ' + ((data[5] << 4) & 0x30) + (data[6] >> 4);
+ if (data[6] & 0xf)
+ sprintf(tmp+7, "-%d", data[6] & 0xf);
+ lprintf(T_ADDR, "%d->%s%s", (data[0] << 6) | ((data[1] >> 2) & 0x3f), strtok(tmp, " "), tmp+7);
+ cmdrsp = (data[1] & 2) ? LAPB_COMMAND : LAPB_RESPONSE;
+ dama = NDAMA_STRING;
+ data += 7;
+ length -= 7;
+ } else {
+ /* Extract the address header */
+ if (length < (AXLEN + AXLEN + 1)) {
+ /* Something wrong with the header */
+ lprintf(T_ERROR, "AX25: bad header!\n");
+ return;
+ }
+
+ if ((data[AXLEN + ALEN] & SSSID_SPARE) == SSSID_SPARE) {
+ extseq = 0;
+ lprintf(T_PROTOCOL, "AX25: ");
+ } else {
+ extseq = 1;
+ lprintf(T_PROTOCOL, "EAX25: ");
+ }
+
+ if ((data[AXLEN + ALEN] & ESSID_SPARE) == ESSID_SPARE)
+ dama = NDAMA_STRING;
+ else
+ dama = DAMA_STRING;
+
+ lprintf(T_ADDR, "%s", pax25(tmp, data + AXLEN));
+ lprintf(T_ADDR, "->%s", pax25(tmp, data));
+
+ cmdrsp = LAPB_UNKNOWN;
+
+ if ((data[ALEN] & C) && !(data[AXLEN + ALEN] & C))
+ cmdrsp = LAPB_COMMAND;
+
+ if ((data[AXLEN + ALEN] & C) && !(data[ALEN] & C))
+ cmdrsp = LAPB_RESPONSE;
+
+ end = (data[AXLEN + ALEN] & HDLCAEB);
+
+ data += (AXLEN + AXLEN);
+ length -= (AXLEN + AXLEN);
+
+ if (!end) {
+ lprintf(T_AXHDR, " v");
+
+ while (!end) {
+ /* Print digi string */
+ lprintf(T_ADDR," %s%s", pax25(tmp, data), (data[ALEN] & REPEATED) ? "*" : "");
+
+ end = (data[ALEN] & HDLCAEB);
+
+ data += AXLEN;
+ length -= AXLEN;
+ }
+ }
+ }
+
+ if (length == 0) return;
+
+ ctlen = ftype(data, &type, &ns, &nr, &pf, extseq);
+
+ data += ctlen;
+ length -= ctlen;
+
+ lprintf(T_AXHDR, " <%s", decode_type(type));
+
+ switch (cmdrsp) {
+ case LAPB_COMMAND:
+ lprintf(T_AXHDR, " C");
+ if (pf) lprintf(T_AXHDR, " P");
+ break;
+ case LAPB_RESPONSE:
+ lprintf(T_AXHDR, " R");
+ if (pf) lprintf(T_AXHDR, " F");
+ break;
+ default:
+ break;
+ }
+
+ if (type == I)
+ lprintf(T_AXHDR, " S%d", ns);
+
+ if ((type & 0x3) != U) /* I or S frame? */
+ lprintf(T_AXHDR, " R%d", nr);
+
+ lprintf(T_AXHDR, ">");
+
+ if (type == I || type == UI) {
+ /* Decode I field */
+ if (length > 0) { /* Get pid */
+ pid = *data++;
+ length--;
+
+ if (pid == PID_SEGMENT) {
+ seg = *data++;
+ length--;
+ lprintf(T_AXHDR, "%s remain %u", seg & SEG_FIRST ? " First seg;" : "", seg & SEG_REM);
+
+ if (seg & SEG_FIRST) {
+ pid = *data++;
+ length--;
+ }
+ }
+
+ switch (pid) {
+ case PID_SEGMENT:
+ lprintf(T_AXHDR,"%s\n", dama);
+ data_dump(data, length, hexdump);
+ break;
+ case PID_ARP:
+ lprintf(T_AXHDR," pid=ARP%s\n", dama);
+ arp_dump(data, length);
+ break;
+ case PID_NETROM:
+ lprintf(T_AXHDR," pid=NET/ROM%s\n", dama);
+ netrom_dump(data, length, hexdump);
+ break;
+ case PID_IP:
+ lprintf(T_AXHDR," pid=IP%s\n", dama);
+ ip_dump(data, length, hexdump);
+ break;
+ case PID_X25:
+ lprintf(T_AXHDR, " pid=X.25%s\n", dama);
+ rose_dump(data, length, hexdump);
+ break;
+ case PID_TEXNET:
+ lprintf(T_AXHDR, " pid=TEXNET%s\n", dama);
+ data_dump(data, length, hexdump);
+ break;
+ case PID_FLEXNET:
+ lprintf(T_AXHDR, " pid=FLEXNET%s\n", dama);
+ flexnet_dump(data, length, hexdump);
+ break;
+ case PID_NO_L3:
+ lprintf(T_AXHDR, " pid=Text%s\n", dama);
+ data_dump(data, length, hexdump);
+ break;
+ default:
+ lprintf(T_AXHDR, " pid=0x%x%s\n", pid, dama);
+ data_dump(data, length, hexdump);
+ break;
+ }
+ }
+ } else if (type == FRMR && length >= 3) {
+ /* FIX ME XXX
+ lprintf(T_AXHDR, ": %s", decode_type(ftype(data[0])));
+ */
+ lprintf(T_AXHDR, ": %02X", data[0]);
+ lprintf(T_AXHDR, " Vr = %d Vs = %d",
+ (data[1] >> 5) & MMASK,
+ (data[1] >> 1) & MMASK);
+ if(data[2] & W)
+ lprintf(T_ERROR, " Invalid control field");
+ if(data[2] & X)
+ lprintf(T_ERROR, " Illegal I-field");
+ if(data[2] & Y)
+ lprintf(T_ERROR, " Too-long I-field");
+ if(data[2] & Z)
+ lprintf(T_ERROR, " Invalid seq number");
+ lprintf(T_AXHDR,"%s\n", dama);
+ } else if ((type == SABM || type == UA) && length >= 2) {
+ /* FlexNet transmits the QSO "handle" for header
+ * compression in SABM and UA frame data fields
+ */
+ lprintf(T_AXHDR," [%d]%s\n", (data[0] << 8) | data[1], dama);
+ } else {
+ lprintf(T_AXHDR,"%s\n", dama);
+ }
+}
+
+static char *decode_type(int type)
+{
+ switch (type) {
+ case I:
+ return "I";
+ case SABM:
+ return "C";
+ case SABME:
+ return "CE";
+ case DISC:
+ return "D";
+ case DM:
+ return "DM";
+ case UA:
+ return "UA";
+ case RR:
+ return "RR";
+ case RNR:
+ return "RNR";
+ case REJ:
+ return "REJ";
+ case FRMR:
+ return "FRMR";
+ case UI:
+ return "UI";
+ default:
+ return "[invalid]";
+ }
+}
+
+char *pax25(char *buf, unsigned char *data)
+{
+ int i, ssid;
+ char *s;
+ char c;
+
+ s = buf;
+
+ for (i = 0; i < ALEN; i++) {
+ c = (data[i] >> 1) & 0x7F;
+
+ if (!isalnum(c) && c != ' ') {
+ strcpy(buf, "[invalid]");
+ return buf;
+ }
+
+ if (c != ' ') *s++ = c;
+ }
+
+ if ((ssid = (data[ALEN] & SSID)) != 0)
+ sprintf(s, "-%d", ssid >> 1);
+ else
+ *s = '\0';
+
+ return(buf);
+}
+
+static int ftype(unsigned char *data, int *type, int *ns, int *nr, int *pf, int extseq)
+{
+ if (extseq) {
+ if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */
+ *type = I;
+ *ns = (*data >> 1) & 127;
+ data++;
+ *nr = (*data >> 1) & 127;
+ *pf = *data & EPF;
+ return 2;
+ }
+ if (*data & 0x02) {
+ *type = *data & ~PF;
+ *pf = *data & PF;
+ return 1;
+ } else {
+ *type = *data;
+ data++;
+ *nr = (*data >> 1) & 127;
+ *pf = *data & EPF;
+ return 2;
+ }
+ } else {
+ if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */
+ *type = I;
+ *ns = (*data >> 1) & 7;
+ *nr = (*data >> 5) & 7;
+ *pf = *data & PF;
+ return 1;
+ }
+ if (*data & 0x02) { /* U-frames use all except P/F bit for type */
+ *type = *data & ~PF;
+ *pf = *data & PF;
+ return 1;
+ } else { /* S-frames use low order 4 bits for type */
+ *type = *data & 0x0F;
+ *nr = (*data >> 5) & 7;
+ *pf = *data & PF;
+ return 1;
+ }
+ }
+}