From 17287576555a5c46fa23549e2e5f073660dccb70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Apr 1999 09:51:03 +0200 Subject: Import ax25-tools 0.0.1 from tarball --- ax25/mheardd.c | 436 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 ax25/mheardd.c (limited to 'ax25/mheardd.c') diff --git a/ax25/mheardd.c b/ax25/mheardd.c new file mode 100644 index 0000000..2d98fad --- /dev/null +++ b/ax25/mheardd.c @@ -0,0 +1,436 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "../pathnames.h" + +#define KISS_MASK 0x0F +#define KISS_DATA 0x00 + +#define PID_SEGMENT 0x08 +#define PID_ARP 0xCD +#define PID_NETROM 0xCF +#define PID_IP 0xCC +#define PID_ROSE 0x01 +#define PID_TEXNET 0xC3 +#define PID_FLEXNET 0xCE +#define PID_TEXT 0xF0 +#define PID_PSATFT 0xBB +#define PID_PSATPB 0xBD + +#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 SSSID_SPARE 0x40 +#define ESSID_SPARE 0x20 + +#define ALEN 6 +#define AXLEN 7 + +struct mheard_list_struct { + int in_use; + struct mheard_struct entry; + long position; +}; + +static struct mheard_list_struct *mheard_list; +static int mheard_list_size = 40; +static int logging = FALSE; + +static int ftype(unsigned char *, int *, int); +static struct mheard_list_struct *findentry(ax25_address *, char *); + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +int main(int argc, char **argv) +{ + struct mheard_list_struct *mheard; + unsigned char buffer[1500], *data; + int size, s; + char *port = NULL; + struct sockaddr sa; + int asize; + long position; + int ctlen, type, end, extseq, flush = FALSE; + FILE *fp; + + while ((s = getopt(argc, argv, "fln:v")) != -1) { + switch (s) { + case 'l': + logging = TRUE; + break; + case 'f': + flush = TRUE; + break; + case 'n': + mheard_list_size = atoi(optarg); + if (mheard_list_size < 10 || mheard_list_size > 100) { + fprintf(stderr, "mheardd: list size must be between 10 and 100\n"); + return 1; + } + break; + case 'v': + printf("mheardd: %s\n", VERSION); + return 0; + case ':': + fprintf(stderr, "mheardd: option -n needs an argument\n"); + return 1; + case '?': + fprintf(stderr, "Usage: mheardd [-f] [-l] [-n number] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "mheardd: no AX.25 port data configured\n"); + return 1; + } + + if ((mheard_list = calloc(mheard_list_size, sizeof(struct mheard_list_struct))) == NULL) { + fprintf(stderr, "mheardd: cannot allocate memory\n"); + return 1; + } + + if (flush) + unlink(DATA_MHEARD_FILE); + + /* Load an existing heard list */ + if ((fp = fopen(DATA_MHEARD_FILE, "r")) != NULL) { + s = 0; + position = ftell(fp); + + while (fread(buffer, sizeof(struct mheard_struct), 1, fp) == 1 && s < mheard_list_size) { + memcpy(&mheard_list[s].entry, buffer, sizeof(struct mheard_struct)); + mheard_list[s].in_use = TRUE; + mheard_list[s].position = position; + position = ftell(fp); + s++; + } + + fclose(fp); + } else { + if ((fp = fopen(DATA_MHEARD_FILE, "w")) != NULL) + fclose(fp); + } + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { + perror("mheardd: socket"); + return 1; + } + + if (!daemon_start(FALSE)) { + fprintf(stderr, "mheardd: cannot become a daemon\n"); + return 1; + } + + /* Use syslog for error messages rather than perror/fprintf */ + if (logging) { + openlog("mheardd", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + asize = sizeof(sa); + + if ((size = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &asize)) == -1) { + if (logging) { + syslog(LOG_ERR, "recv: %m"); + closelog(); + } + return 1; + } + + if ((port = ax25_config_get_name(sa.sa_data)) == NULL) { + if (logging) + syslog(LOG_WARNING, "unknown port '%s'\n", sa.sa_data); + continue; + } + + data = buffer; + + if ((*data & KISS_MASK) != KISS_DATA) + continue; + + data++; + size--; + + if (size < (AXLEN + AXLEN + 1)) { + if (logging) + syslog(LOG_WARNING, "packet too short\n"); + continue; + } + + mheard = findentry((ax25_address *)(data + AXLEN), port); + + if (!ax25_validate(data + 0) || !ax25_validate(data + AXLEN)) { + if (logging) + syslog(LOG_WARNING, "invalid callsign on port %s\n", port); + continue; + } + + memcpy(&mheard->entry.from_call, data + AXLEN, sizeof(ax25_address)); + memcpy(&mheard->entry.to_call, data + 0, sizeof(ax25_address)); + strcpy(mheard->entry.portname, port); + mheard->entry.ndigis = 0; + + extseq = ((data[AXLEN + ALEN] & SSSID_SPARE) != SSSID_SPARE); + end = (data[AXLEN + ALEN] & HDLCAEB); + + data += (AXLEN + AXLEN); + size -= (AXLEN + AXLEN); + + while (!end) { + memcpy(&mheard->entry.digis[mheard->entry.ndigis], data, sizeof(ax25_address)); + mheard->entry.ndigis++; + + end = (data[ALEN] & HDLCAEB); + + data += AXLEN; + size -= AXLEN; + } + + if (size == 0) { + if (logging) + syslog(LOG_WARNING, "packet too short\n"); + continue; + } + + ctlen = ftype(data, &type, extseq); + + mheard->entry.count++; + + switch (type) { + case SABM: + mheard->entry.type = MHEARD_TYPE_SABM; + mheard->entry.uframes++; + break; + case SABME: + mheard->entry.type = MHEARD_TYPE_SABME; + mheard->entry.uframes++; + break; + case DISC: + mheard->entry.type = MHEARD_TYPE_DISC; + mheard->entry.uframes++; + break; + case UA: + mheard->entry.type = MHEARD_TYPE_UA; + mheard->entry.uframes++; + break; + case DM: + mheard->entry.type = MHEARD_TYPE_DM; + mheard->entry.uframes++; + break; + case RR: + mheard->entry.type = MHEARD_TYPE_RR; + mheard->entry.sframes++; + break; + case RNR: + mheard->entry.type = MHEARD_TYPE_RNR; + mheard->entry.sframes++; + break; + case REJ: + mheard->entry.type = MHEARD_TYPE_REJ; + mheard->entry.sframes++; + break; + case FRMR: + mheard->entry.type = MHEARD_TYPE_FRMR; + mheard->entry.uframes++; + break; + case I: + mheard->entry.type = MHEARD_TYPE_I; + mheard->entry.iframes++; + break; + case UI: + mheard->entry.type = MHEARD_TYPE_UI; + mheard->entry.uframes++; + break; + default: + if (logging) + syslog(LOG_WARNING, "unknown packet type %02X\n", *data); + mheard->entry.type = MHEARD_TYPE_UNKNOWN; + break; + } + + data += ctlen; + size -= ctlen; + + if (type == I || type == UI) { + switch (*data) { + case PID_TEXT: + mheard->entry.mode |= MHEARD_MODE_TEXT; + break; + case PID_SEGMENT: + mheard->entry.mode |= MHEARD_MODE_SEGMENT; + break; + case PID_ARP: + mheard->entry.mode |= MHEARD_MODE_ARP; + break; + case PID_NETROM: + mheard->entry.mode |= MHEARD_MODE_NETROM; + break; + case PID_IP: + mheard->entry.mode |= (type == I) ? MHEARD_MODE_IP_VC : MHEARD_MODE_IP_DG; + break; + case PID_ROSE: + mheard->entry.mode |= MHEARD_MODE_ROSE; + break; + case PID_TEXNET: + mheard->entry.mode |= MHEARD_MODE_TEXNET; + break; + case PID_FLEXNET: + mheard->entry.mode |= MHEARD_MODE_FLEXNET; + break; + case PID_PSATPB: + mheard->entry.mode |= MHEARD_MODE_PSATPB; + break; + case PID_PSATFT: + mheard->entry.mode |= MHEARD_MODE_PSATFT; + break; + default: + if (logging) + syslog(LOG_WARNING, "unknown PID %02X\n", *data); + mheard->entry.mode |= MHEARD_MODE_UNKNOWN; + break; + } + } + + if (mheard->entry.first_heard == 0) + time(&mheard->entry.first_heard); + + time(&mheard->entry.last_heard); + + if ((fp = fopen(DATA_MHEARD_FILE, "r+")) == NULL) { + if (logging) + syslog(LOG_ERR, "cannot open mheard data file\n"); + continue; + } + + if (mheard->position == 0xFFFFFF) { + fseek(fp, 0L, SEEK_END); + mheard->position = ftell(fp); + } + + fseek(fp, mheard->position, SEEK_SET); + + fwrite(&mheard->entry, sizeof(struct mheard_struct), 1, fp); + + fclose(fp); + } +} + +static int ftype(unsigned char *data, int *type, int extseq) +{ + if (extseq) { + if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */ + *type = I; + return 2; + } + if (*data & 0x02) { + *type = *data & ~PF; + return 1; + } else { + *type = *data; + return 2; + } + } else { + if ((*data & 0x01) == 0) { /* An I frame is an I-frame ... */ + *type = I; + return 1; + } + if (*data & 0x02) { /* U-frames use all except P/F bit for type */ + *type = *data & ~PF; + return 1; + } else { /* S-frames use low order 4 bits for type */ + *type = *data & 0x0F; + return 1; + } + } +} + +static struct mheard_list_struct *findentry(ax25_address *callsign, char *port) +{ + struct mheard_list_struct *oldest = NULL; + int i; + + for (i = 0; i < mheard_list_size; i++) + if (mheard_list[i].in_use && + ax25_cmp(&mheard_list[i].entry.from_call, callsign) == 0 && + strcmp(mheard_list[i].entry.portname, port) == 0) + return mheard_list + i; + + for (i = 0; i < mheard_list_size; i++) { + if (!mheard_list[i].in_use) { + mheard_list[i].in_use = TRUE; + mheard_list[i].position = 0xFFFFFF; + return mheard_list + i; + } + } + + for (i = 0; i < mheard_list_size; i++) { + if (mheard_list[i].in_use) { + if (oldest == NULL) { + oldest = mheard_list + i; + } else { + if (mheard_list[i].entry.last_heard < oldest->entry.last_heard) + oldest = mheard_list + i; + } + } + } + + memset(&oldest->entry, 0x00, sizeof(struct mheard_struct)); + + return oldest; +} -- cgit v1.2.3