2020-07-02 23:54:48 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#include <patty/ax25.h>
|
|
|
|
#include <patty/print.h>
|
|
|
|
|
|
|
|
#define printable(c) \
|
|
|
|
(c >= 0x20 && c < 0x7f)
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
static char *frame_type(enum patty_ax25_frame_type type) {
|
2020-07-10 00:01:50 -04:00
|
|
|
switch (type) {
|
|
|
|
case PATTY_AX25_FRAME_I: return "I";
|
|
|
|
case PATTY_AX25_FRAME_RR: return "RR";
|
|
|
|
case PATTY_AX25_FRAME_RNR: return "RNR";
|
|
|
|
case PATTY_AX25_FRAME_REJ: return "REJ";
|
|
|
|
case PATTY_AX25_FRAME_SREJ: return "SREJ";
|
|
|
|
case PATTY_AX25_FRAME_SABM: return "SABM";
|
|
|
|
case PATTY_AX25_FRAME_SABME: return "SABME";
|
|
|
|
case PATTY_AX25_FRAME_DISC: return "DISC";
|
|
|
|
case PATTY_AX25_FRAME_DM: return "DM";
|
|
|
|
case PATTY_AX25_FRAME_UA: return "UA";
|
|
|
|
case PATTY_AX25_FRAME_FRMR: return "FRMR";
|
|
|
|
case PATTY_AX25_FRAME_UI: return "UI";
|
|
|
|
case PATTY_AX25_FRAME_XID: return "XID";
|
|
|
|
case PATTY_AX25_FRAME_TEST: return "TEST";
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
static char *frame_cr(enum patty_ax25_frame_cr cr) {
|
|
|
|
switch (cr) {
|
2020-08-03 18:51:42 -04:00
|
|
|
case PATTY_AX25_FRAME_COMMAND: return "cmd";
|
|
|
|
case PATTY_AX25_FRAME_RESPONSE: return "res";
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2020-07-14 17:04:49 -04:00
|
|
|
}
|
|
|
|
|
2020-08-03 18:51:42 -04:00
|
|
|
return "?";
|
2020-07-14 17:04:49 -04:00
|
|
|
}
|
|
|
|
|
2020-07-02 23:54:48 -04:00
|
|
|
static int print_addr(FILE *fh, const patty_ax25_addr *addr) {
|
|
|
|
char buf[7];
|
|
|
|
uint8_t ssid;
|
|
|
|
|
|
|
|
if (patty_ax25_ntop(addr, buf, &ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(fh, "%s", buf);
|
|
|
|
|
|
|
|
if (ssid) {
|
2020-08-03 18:51:42 -04:00
|
|
|
fprintf(fh, "-%d", (int)ssid);
|
2020-07-02 23:54:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_ntop:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int print_frame_addrs(FILE *fh, const patty_ax25_frame *frame) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
print_addr(fh, &frame->src);
|
|
|
|
|
2020-08-03 18:51:42 -04:00
|
|
|
fprintf(fh, ">");
|
2020-07-02 23:54:48 -04:00
|
|
|
|
|
|
|
for (i=0; i<frame->hops; i++) {
|
|
|
|
print_addr(fh, &frame->repeaters[i]);
|
2020-08-03 18:51:42 -04:00
|
|
|
fprintf(fh, ">");
|
2020-07-02 23:54:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
print_addr(fh, &frame->dest);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-17 22:57:23 -04:00
|
|
|
int patty_print_frame_header(FILE *fh,
|
|
|
|
const patty_ax25_frame *frame) {
|
2020-07-02 23:54:48 -04:00
|
|
|
if (print_frame_addrs(fh, frame) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2020-07-10 00:01:50 -04:00
|
|
|
if (PATTY_AX25_FRAME_CONTROL_I(frame->control)) {
|
2020-08-04 20:54:43 -04:00
|
|
|
if (fprintf(fh, " (%s %s N(R)=%d N(S)=%d P/F=%d info=%zu)",
|
2020-07-14 17:04:49 -04:00
|
|
|
frame_type(frame->type),
|
|
|
|
frame_cr(frame->cr),
|
2020-07-10 00:01:50 -04:00
|
|
|
(int)frame->nr,
|
|
|
|
(int)frame->ns,
|
|
|
|
(int)frame->pf,
|
2020-07-02 23:54:48 -04:00
|
|
|
frame->infolen) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
2020-07-10 00:01:50 -04:00
|
|
|
} else if (PATTY_AX25_FRAME_CONTROL_U(frame->control)) {
|
2020-08-04 20:54:43 -04:00
|
|
|
if (fprintf(fh, " (%s %s P/F=%d",
|
2020-07-14 17:04:49 -04:00
|
|
|
frame_type(frame->type),
|
|
|
|
frame_cr(frame->cr),
|
2020-07-10 00:01:50 -04:00
|
|
|
(int)frame->pf) < 0) {
|
2020-07-08 18:34:02 -04:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2020-07-10 00:01:50 -04:00
|
|
|
if (PATTY_AX25_FRAME_CONTROL_UI(frame->control)) {
|
2020-08-03 18:51:42 -04:00
|
|
|
if (fprintf(fh, " info=%zu", frame->infolen) < 0) {
|
2020-07-08 18:34:02 -04:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 18:51:42 -04:00
|
|
|
|
|
|
|
if (fprintf(fh, ")") < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
2020-07-10 00:01:50 -04:00
|
|
|
} else if (PATTY_AX25_FRAME_CONTROL_S(frame->control)) {
|
2020-08-04 20:54:43 -04:00
|
|
|
if (fprintf(fh, " (%s %s N(R)=%d P/F=%d)",
|
2020-07-14 17:04:49 -04:00
|
|
|
frame_type(frame->type),
|
|
|
|
frame_cr(frame->cr),
|
2020-07-10 00:01:50 -04:00
|
|
|
(int)frame->nr,
|
|
|
|
(int)frame->pf) < 0) {
|
2020-07-02 23:54:48 -04:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 22:57:23 -04:00
|
|
|
return fprintf(fh, "\n");
|
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_print_params(FILE *fh,
|
|
|
|
const patty_ax25_params *params) {
|
|
|
|
static const struct {
|
|
|
|
enum patty_ax25_param_classes flag;
|
|
|
|
char *name;
|
|
|
|
} classes_flags[] = {
|
|
|
|
{ PATTY_AX25_PARAM_CLASSES_ABM, "ABM" },
|
|
|
|
{ PATTY_AX25_PARAM_CLASSES_HALF_DUPLEX, "half-duplex" },
|
|
|
|
{ PATTY_AX25_PARAM_CLASSES_FULL_DUPLEX, "full-duplex" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
enum patty_ax25_param_hdlc flag;
|
|
|
|
char *name;
|
|
|
|
} hdlc_flags[] = {
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_REJ, "REJ" },
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_SREJ, "SREJ" },
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_XADDR, "extended addresses" },
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_MODULO_8, "modulo 8" },
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_MODULO_128, "modulo 128" },
|
|
|
|
{ PATTY_AX25_PARAM_HDLC_TEST, "TEST" },
|
2020-08-03 02:54:49 -04:00
|
|
|
{ PATTY_AX25_PARAM_HDLC_FCS_16, "16-bit FCS" },
|
2020-07-17 22:57:23 -04:00
|
|
|
{ PATTY_AX25_PARAM_HDLC_SYNC_TX, "synchronous TX" },
|
2020-08-03 02:54:49 -04:00
|
|
|
{ PATTY_AX25_PARAM_HDLC_SREJ_MULTI, "multiple SREJ" },
|
2020-07-17 22:57:23 -04:00
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct {
|
|
|
|
enum patty_ax25_param_type flag;
|
|
|
|
size_t value;
|
|
|
|
char *name;
|
|
|
|
} fields[] = {
|
2020-08-02 19:14:57 -04:00
|
|
|
{ PATTY_AX25_PARAM_INFO_TX, params->info_tx >> 3, "I Field Length TX" },
|
|
|
|
{ PATTY_AX25_PARAM_INFO_RX, params->info_rx >> 3, "I Field Length RX" },
|
|
|
|
{ PATTY_AX25_PARAM_WINDOW_TX, params->window_tx, "Window Size TX" },
|
|
|
|
{ PATTY_AX25_PARAM_WINDOW_RX, params->window_rx, "Window Size RX" },
|
|
|
|
{ PATTY_AX25_PARAM_ACK, params->ack, "Ack timer" },
|
|
|
|
{ PATTY_AX25_PARAM_RETRY, params->retry, "Retry" },
|
2020-07-17 22:57:23 -04:00
|
|
|
{ 0, 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (fprintf(fh, " XID parameters:\n") < 0) {
|
|
|
|
goto error_fprintf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fprintf(fh, " Classes of procedures:\n") < 0) {
|
|
|
|
goto error_fprintf;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; classes_flags[i].name; i++) {
|
|
|
|
if (params->classes & classes_flags[i].flag) {
|
|
|
|
if (fprintf(fh, " > %s\n", classes_flags[i].name) < 0) {
|
|
|
|
goto error_fprintf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(fh, " HDLC optional functions:\n");
|
|
|
|
|
|
|
|
for (i=0; hdlc_flags[i].name; i++) {
|
|
|
|
if (params->hdlc & hdlc_flags[i].flag) {
|
|
|
|
if (fprintf(fh, " > %s\n", hdlc_flags[i].name) < 0) {
|
|
|
|
goto error_fprintf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; fields[i].name; i++) {
|
2020-07-18 15:03:52 -04:00
|
|
|
if (params->flags & (1 << fields[i].flag)) {
|
2020-07-17 22:57:23 -04:00
|
|
|
if (fprintf(fh, " %s: %zu\n", fields[i].name, fields[i].value) < 0) {
|
|
|
|
goto error_fprintf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_fprintf:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_print_hexdump(FILE *fh, void *data, size_t len) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i=0; i<len; i+=16) {
|
|
|
|
size_t x;
|
|
|
|
|
|
|
|
if (fprintf(fh, "%08lx:", i) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
2020-07-02 23:54:48 -04:00
|
|
|
|
2020-07-17 22:57:23 -04:00
|
|
|
for (x=0; x<16; x++) {
|
|
|
|
if (!(x & 1)) {
|
|
|
|
if (fprintf(fh, " ") < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i+x < len) {
|
|
|
|
if (fprintf(fh, "%02x", ((uint8_t *)data)[i+x]) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (fprintf(fh, " ") < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fprintf(fh, " ") < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x=0; x<16 && i+x<len; x++) {
|
|
|
|
uint8_t c = ((uint8_t *)data)[i+x];
|
|
|
|
|
|
|
|
if (fputc(printable(c)? c: '.', fh) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fprintf(fh, "\n") < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-07-02 23:54:48 -04:00
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|