summaryrefslogtreecommitdiffstats
path: root/axutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'axutils.c')
-rw-r--r--axutils.c321
1 files changed, 321 insertions, 0 deletions
diff --git a/axutils.c b/axutils.c
new file mode 100644
index 0000000..49c27be
--- /dev/null
+++ b/axutils.c
@@ -0,0 +1,321 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <sys/socket.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include "axlib.h"
+
+ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
+
+/*
+ * Library routine for callsign conversion.
+ */
+
+int convert_call_entry(const char *name, char *buf)
+{
+ int ct = 0;
+ int ssid = 0;
+ const char *p = name;
+ char c;
+
+ while (ct < 6) {
+ c = toupper(*p);
+
+ if (c == '-' || c == '\0')
+ break;
+
+ if (!isalnum(c)) {
+ printf("axutils: invalid symbol in callsign %s\n", name);
+ return -1;
+ }
+
+ buf[ct] = c << 1;
+
+ p++;
+ ct++;
+ }
+
+ while (ct < 6) {
+ buf[ct] = ' ' << 1;
+ ct++;
+ }
+
+ if (*p != '\0') {
+ p++;
+
+ if (sscanf(p, "%d", &ssid) != 1 || ssid < 0 || ssid > 15) {
+ printf("axutils: SSID must follow '-' and be numeric in the range 0-15 - %s\n", name);
+ return -1;
+ }
+ }
+
+ buf[6] = ((ssid + '0') << 1) & 0x1E;
+
+ return 0;
+}
+
+int convert_call(char *call, struct full_sockaddr_ax25 *sax)
+{
+ char *bp, *np;
+ char *addrp;
+ int n = 0;
+ char *tmp = strdup(call);
+
+ if (tmp == NULL)
+ return -1;
+
+ bp = tmp;
+
+ addrp = sax->fsa_ax25.sax25_call.ax25_call;
+
+ do {
+ /* Fetch one callsign token */
+ while (*bp != '\0' && isspace(*bp))
+ bp++;
+
+ np = bp;
+
+ while (*np != '\0' && !isspace(*np))
+ np++;
+
+ if (*np != '\0')
+ *np++ = '\0';
+
+ /* Check for the optional 'via' syntax */
+ if (n == 1 && (strcasecmp(bp, "V") == 0 || strcasecmp(bp, "VIA") == 0)) {
+ bp = np;
+ continue;
+ }
+
+ /* Process the token */
+ if (convert_call_entry(bp, addrp) == -1) {
+ free(tmp);
+ return -1;
+ }
+
+ /* Move along */
+ bp = np;
+ n++;
+
+ if (n == 1)
+ addrp = sax->fsa_digipeater[0].ax25_call; /* First digipeater address */
+ else
+ addrp += sizeof(ax25_address);
+
+ } while (n < AX25_MAX_DIGIS && *bp);
+
+ free(tmp);
+
+ /* Tidy up */
+ sax->fsa_ax25.sax25_ndigis = n - 1;
+ sax->fsa_ax25.sax25_family = AF_AX25;
+
+ return sizeof(struct full_sockaddr_ax25);
+}
+
+int convert_call_arglist(char *call[], struct full_sockaddr_ax25 *sax)
+{
+ char *bp;
+ char *addrp;
+ int n = 0;
+ int argp = 0;
+
+ addrp = sax->fsa_ax25.sax25_call.ax25_call;
+
+ do {
+ /* Fetch one callsign token */
+ if ((bp = call[argp++]) == NULL)
+ break;
+
+ /* Check for the optional 'via' syntax */
+ if (n == 1 && (strcasecmp(bp, "V") == 0 || strcasecmp(bp, "VIA") == 0))
+ continue;
+
+ /* Process the token */
+ if (convert_call_entry(bp, addrp) == -1)
+ return -1;
+
+ n++;
+
+ if (n == 1)
+ addrp = sax->fsa_digipeater[0].ax25_call; /* First digipeater address */
+ else
+ addrp += sizeof(ax25_address);
+
+ } while (n < AX25_MAX_DIGIS && call[argp] != NULL);
+
+ /* Tidy up */
+ sax->fsa_ax25.sax25_ndigis = n - 1;
+ sax->fsa_ax25.sax25_family = AF_AX25;
+
+ return sizeof(struct full_sockaddr_ax25);
+}
+
+/*
+ * Library routine for Rose address conversion.
+ */
+
+int convert_rose_address(const char *addr, char *buf)
+{
+ int i, n;
+
+ if (strlen(addr) != 10) {
+ printf("axutils: invalid rose address length\n");
+ return -1;
+ }
+
+ if (strspn(addr, "0123456789") != 10) {
+ printf("axutils: invalid characters in address\n");
+ return -1;
+ }
+
+ for (n = 0, i = 0; i < 5; i++, n += 2) {
+ buf[i] = (addr[n + 0] - '0') << 4;
+ buf[i] |= (addr[n + 1] - '0') << 0;
+ }
+
+ return 0;
+}
+
+/*
+ * ax25 -> ascii conversion
+ */
+char *ax2asc(ax25_address *a)
+{
+ static char buf[11];
+ char c, *s;
+ int n;
+
+ for (n = 0, s = buf; n < 6; n++) {
+ c = (a->ax25_call[n] >> 1) & 0x7F;
+
+ if (c != ' ') *s++ = c;
+ }
+
+ *s++ = '-';
+
+ if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
+ *s++ = '1';
+ n -= 10;
+ }
+
+ *s++ = n + '0';
+ *s++ = '\0';
+
+ return buf;
+}
+
+/*
+ * rose -> ascii conversion
+ */
+char *rose2asc(rose_address *a)
+{
+ static char buf[11];
+
+ sprintf(buf, "%02X%02X%02X%02X%02X", a->rose_addr[0] & 0xFF,
+ a->rose_addr[1] & 0xFF,
+ a->rose_addr[2] & 0xFF,
+ a->rose_addr[3] & 0xFF,
+ a->rose_addr[4] & 0xFF);
+
+ return buf;
+}
+
+/*
+ * Compare two ax.25 addresses
+ */
+int ax25cmp(ax25_address *a, ax25_address *b)
+{
+ if ((a->ax25_call[0] & 0xFE) != (b->ax25_call[0] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[1] & 0xFE) != (b->ax25_call[1] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[2] & 0xFE) != (b->ax25_call[2] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[3] & 0xFE) != (b->ax25_call[3] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[4] & 0xFE) != (b->ax25_call[4] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[5] & 0xFE) != (b->ax25_call[5] & 0xFE))
+ return 1;
+
+ if ((a->ax25_call[6] & 0x1E) != (b->ax25_call[6] & 0x1E)) /* SSID without control bit */
+ return 2;
+
+ return 0;
+}
+
+/*
+ * Compare two Rose addresses
+ */
+int rosecmp(rose_address *a, rose_address *b)
+{
+ int i;
+
+ for (i = 0; i < 5; i++)
+ if (a->rose_addr[i] != b->rose_addr[i])
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Validate an AX.25 callsign.
+ */
+int ax25validate(char *call)
+{
+ unsigned char s[7];
+ int n;
+
+ for (n = 0; n < 6; n++)
+ s[n] = (call[n] >> 1) & 0x7F;
+ s[6] = '\0';
+
+ if (strspn(s, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ") == 6)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Convert a string to upper case
+ */
+char *strupr(char *s)
+{
+ char *p;
+
+ if (s == NULL)
+ return NULL;
+
+ for (p = s; *p != '\0'; p++)
+ *p = toupper(*p);
+
+ return s;
+}
+
+/*
+ * Convert a string to lower case
+ */
+char *strlwr(char *s)
+{
+ char *p;
+
+ if (s == NULL)
+ return NULL;
+
+ for (p = s; *p != '\0'; p++)
+ *p = tolower(*p);
+
+ return s;
+}