summaryrefslogtreecommitdiffstats
path: root/ax25ipd
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-07 10:23:42 +0200
committerRalf Baechle <ralf@linux-mips.org>1999-06-07 10:23:42 +0200
commit0fceb64d25ff3d9586549bb43d971c5eef904330 (patch)
treed4799d0fd53a3d8ae342c84f8ad4fb2ca2f14de0 /ax25ipd
Import ax25-apps 0.0.1 from tarballax25-apps-0.0.1
Diffstat (limited to 'ax25ipd')
-rw-r--r--ax25ipd/Makefile.am19
-rw-r--r--ax25ipd/Makefile.in404
-rw-r--r--ax25ipd/ax25ipd.864
-rw-r--r--ax25ipd/ax25ipd.c163
-rw-r--r--ax25ipd/ax25ipd.conf.5159
-rw-r--r--ax25ipd/ax25ipd.h182
-rw-r--r--ax25ipd/config.c404
-rw-r--r--ax25ipd/crc.c171
-rw-r--r--ax25ipd/io.c574
-rw-r--r--ax25ipd/kiss.c201
-rw-r--r--ax25ipd/process.c338
-rw-r--r--ax25ipd/routing.c264
12 files changed, 2943 insertions, 0 deletions
diff --git a/ax25ipd/Makefile.am b/ax25ipd/Makefile.am
new file mode 100644
index 0000000..1572b25
--- /dev/null
+++ b/ax25ipd/Makefile.am
@@ -0,0 +1,19 @@
+
+sbin_PROGRAMS = ax25ipd
+
+man_MANS = ax25ipd.8 ax25ipd.conf.5
+
+EXTRA_DIST = $(man_MANS)
+
+CFLAGS = -DUSE_TERMIO
+ax25ipd_LDADD = $(AX25_LIB)
+
+ax25ipd_SOURCES = \
+ config.c \
+ crc.c \
+ io.c \
+ kiss.c \
+ ax25ipd.c \
+ ax25ipd.h \
+ process.c \
+ routing.c
diff --git a/ax25ipd/Makefile.in b/ax25ipd/Makefile.in
new file mode 100644
index 0000000..2876a26
--- /dev/null
+++ b/ax25ipd/Makefile.in
@@ -0,0 +1,404 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+AWK = @AWK@
+AX25_LIB = @AX25_LIB@
+CC = @CC@
+DLLTOOL = @DLLTOOL@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+NCURSES_LIB = @NCURSES_LIB@
+NM = @NM@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+sbin_PROGRAMS = ax25ipd
+
+man_MANS = ax25ipd.8 ax25ipd.conf.5
+
+EXTRA_DIST = $(man_MANS)
+
+CFLAGS = -DUSE_TERMIO
+ax25ipd_LDADD = $(AX25_LIB)
+
+ax25ipd_SOURCES = config.c crc.c io.c kiss.c ax25ipd.c ax25ipd.h process.c routing.c
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(sbin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+ax25ipd_OBJECTS = config.o crc.o io.o kiss.o ax25ipd.o process.o \
+routing.o
+ax25ipd_DEPENDENCIES =
+ax25ipd_LDFLAGS =
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(ax25ipd_SOURCES)
+OBJECTS = $(ax25ipd_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ax25ipd/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-sbinPROGRAMS:
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+distclean-sbinPROGRAMS:
+
+maintainer-clean-sbinPROGRAMS:
+
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+ax25ipd: $(ax25ipd_OBJECTS) $(ax25ipd_DEPENDENCIES)
+ @rm -f ax25ipd
+ $(LINK) $(ax25ipd_LDFLAGS) $(ax25ipd_OBJECTS) $(ax25ipd_LDADD) $(LIBS)
+
+install-man5:
+ $(mkinstalldirs) $(DESTDIR)$(man5dir)
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+uninstall-man5:
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+install-man8:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+
+uninstall-man8:
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ax25ipd
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ax25ipd.o: ax25ipd.c ../config.h ../pathnames.h ax25ipd.h
+config.o: config.c ax25ipd.h ../pathnames.h
+crc.o: crc.c ax25ipd.h ../pathnames.h
+io.o: io.c ax25ipd.h ../pathnames.h
+kiss.o: kiss.c ax25ipd.h ../pathnames.h
+process.o: process.c ax25ipd.h ../pathnames.h
+routing.o: routing.c ax25ipd.h ../pathnames.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-sbinPROGRAMS
+install-exec: install-exec-am
+
+install-data-am: install-man
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-sbinPROGRAMS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man5 \
+ $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-sbinPROGRAMS clean-compile clean-libtool clean-tags \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-sbinPROGRAMS distclean-compile \
+ distclean-libtool distclean-tags distclean-generic \
+ clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-sbinPROGRAMS \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \
+clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
+install-sbinPROGRAMS mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile mostlyclean-libtool \
+distclean-libtool clean-libtool maintainer-clean-libtool install-man5 \
+uninstall-man5 install-man8 uninstall-man8 install-man uninstall-man \
+tags mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ax25ipd/ax25ipd.8 b/ax25ipd/ax25ipd.8
new file mode 100644
index 0000000..dc0e7b1
--- /dev/null
+++ b/ax25ipd/ax25ipd.8
@@ -0,0 +1,64 @@
+.TH AX25IPD 1 "2 February 1997" Linux "Linux Programmer's Manual"
+.SH NAME
+ax25ipd \- AX.25 into IP Encapsulator
+.SH SYNOPSIS
+.B ax25ipd [config-file]
+.SH DESCRIPTION
+.LP
+.B ax25ipd
+is an RFC1226 compliant daemon capable of providing the encapsualtion
+neccessary to send and receive AX.25 traffic across an IP transport.
+.LP
+Normally invoked as part of the boot order network initialisation,
+.B ax25ipd
+is capable of talking directly to a serial port connected tnc, or over
+a pipe to a linux AX.25 port. KAM DE Dual Port Kiss is also supported
+in this release.
+.LP
+.B ax25ipd
+can be run as a pure encapsulator, or as a digital repeater with a
+functional callsign. Destination IP addresses are determined from a
+hardcoded map of callsign/IP Address pairs.
+.LP
+.B ax25ipd
+defaults to using
+.B /etc/ax25/ax25ipd.conf
+as it's config file ...
+.LP
+.SH OPTIONS
+.TP 10
+.BI \-v
+Display the version. (yet to be implemented ...)
+.SH FILES
+/etc/ax25/ax25ipd.conf
+.SH "SEE ALSO"
+.BR ax25ipd.conf
+.BR beacon (1),
+.BR ax25 (4),
+.BR netrom (4),
+.BR rose (4),
+.BR kissattach (8).
+.LP
+.SH BUGS
+Routing needs to be looked at seriously, the method of routing is a real
+hack, and improvements to it have only added to the hack.
+.LP
+Logging needs to be properly implemented.
+.LP
+Command line parsing needs to be properly implemented.
+.LP
+.B ax25ipd
+should be part of the Linux AX.25 kernel support probably :-)
+.SH AUTHORS
+.nf
+Michael Westerhof <Mike.Westerhof@Central.Sun.COM> <invalid address>
+.br
+Michael Durrant <>
+.br
+D. Jeff Dionne VE3DJF <Jeff@lnx_rpi.ee.ryerson.ca>
+.br
+Rob Mayfield VK5XXX/VK5ZEU <mayfieldrob@mail.dec.com>
+.br
+Terry Dawson VK2KTJ <terry@perf.no.itg.telstra.com.au>
+.br
+.fi
diff --git a/ax25ipd/ax25ipd.c b/ax25ipd/ax25ipd.c
new file mode 100644
index 0000000..107ad5f
--- /dev/null
+++ b/ax25ipd/ax25ipd.c
@@ -0,0 +1,163 @@
+/* ax25ipd.c main entrypoint
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ */
+
+/*
+ * cleaned up and prototyped for inclusion into the standard linux ax25
+ * toolset in january 1997 by rob mayfield, vk5xxx/vk5zeu
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#include <netax25/daemon.h>
+#include <config.h>
+
+#include "../pathnames.h"
+#include "ax25ipd.h"
+
+jmp_buf restart_env;
+
+/* Prototypes */
+void hupper(int);
+
+int
+main(int argc, char **argv)
+{
+ if(setjmp(restart_env)==0) {
+ signal(SIGHUP, hupper);
+ }
+
+ /* set up the handler for statistics reporting */
+ signal(SIGUSR1, usr1_handler);
+ signal(SIGINT, int_handler);
+ signal(SIGTERM, term_handler);
+
+ /* Say hello to the world */
+ greet_world();
+
+ /* Test arguments */
+ if(argc>2){
+ fprintf(stderr,"Usage: %s [<configuration-file>]\n",argv[0]);
+ exit(1);
+ }
+
+ /* Initialize all routines */
+ config_init();
+ kiss_init();
+ route_init();
+ process_init();
+ io_init();
+
+ /* read config file */
+ config_read(argv[1]);
+
+ /* print the current config and route info */
+ dump_config();
+ dump_routes();
+ dump_params();
+
+ /* Open the IO stuff */
+ io_open();
+
+ /* if we get this far without error, let's fork off ! :-) */
+ if (!daemon_start(TRUE)) {
+ fprintf(stderr, "ax25ipd: cannot become a daemon\n");
+ return 1;
+ }
+
+ /* and let the games begin */
+ io_start();
+
+ return(0);
+}
+
+
+void
+greet_world()
+{
+ printf("\nax25ipd %s / %s\n", VERS2, VERSION);
+ printf("Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.\n");
+ printf("This software may be freely used, distributed, or modified, providing\nthis header is not removed\n\n");
+ fflush(stdout);
+}
+
+void
+do_stats()
+{
+ int save_loglevel;
+
+/* save the old loglevel, and force at least loglevel 1 */
+ save_loglevel = loglevel;
+ loglevel = 1;
+
+ printf("\nSIGUSR1 signal: statistics and configuration report\n");
+
+ greet_world();
+
+ dump_config();
+ dump_routes();
+ dump_params();
+
+ printf("\nInput stats:\n");
+ printf("KISS input packets: %d\n",stats.kiss_in);
+ printf(" too big: %d\n",stats.kiss_toobig);
+ printf(" bad type: %d\n",stats.kiss_badtype);
+ printf(" too short: %d\n",stats.kiss_tooshort);
+ printf(" not for me: %d\n",stats.kiss_not_for_me);
+ printf(" I am destination: %d\n",stats.kiss_i_am_dest);
+ printf(" no route found: %d\n",stats.kiss_no_ip_addr);
+ printf("UDP input packets: %d\n",stats.udp_in);
+ printf("IP input packets: %d\n",stats.ip_in);
+ printf(" failed CRC test: %d\n",stats.ip_failed_crc);
+ printf(" too short: %d\n",stats.ip_tooshort);
+ printf(" not for me: %d\n",stats.ip_not_for_me);
+ printf(" I am destination: %d\n",stats.ip_i_am_dest);
+ printf("\nOutput stats:\n");
+ printf("KISS output packets: %d\n",stats.kiss_out);
+ printf(" beacons: %d\n",stats.kiss_beacon_outs);
+ printf("UDP output packets: %d\n",stats.udp_out);
+ printf("IP output packets: %d\n",stats.ip_out);
+ printf("\n");
+
+ fflush(stdout);
+
+/* restore the old loglevel */
+ loglevel = save_loglevel;
+}
+
+void
+hupper(int i)
+{
+ printf("\nSIGHUP!\n");
+ longjmp(restart_env, 1);
+}
+
+void
+usr1_handler(int i)
+{
+ printf("\nSIGUSR1!\n");
+ do_stats();
+}
+
+void
+int_handler(int i)
+{
+ printf("\nSIGINT!\n");
+ do_stats();
+ exit(1);
+}
+
+void
+term_handler(int i)
+{
+ printf("\nSIGTERM!\n");
+ do_stats();
+ exit(1);
+}
+
diff --git a/ax25ipd/ax25ipd.conf.5 b/ax25ipd/ax25ipd.conf.5
new file mode 100644
index 0000000..73ea569
--- /dev/null
+++ b/ax25ipd/ax25ipd.conf.5
@@ -0,0 +1,159 @@
+.TH AX25IPD.CONF 5 "7 July 1997" Linux "Linux Programmer's Manual"
+.SH NAME
+ax25ipd.conf \- Control the operation of ax25ipd.
+.SH DESCRIPTION
+.LP
+The
+.B ax25ipd.conf
+file controls the operation of the ax25ipd(8) program. The operation of the
+config file can best be seen in an example:
+.LP
+#
+.br
+# ax25ipd configuration file for station floyd.vk5xxx.ampr.org
+.br
+#
+.br
+# Select axip transport. 'ip' is what you want for compatibility
+.br
+# with most other gates ...
+.br
+#
+.br
+socket ip
+.br
+#
+.br
+# Set ax25ipd mode of operation. (digi or tnc)
+.br
+#
+.br
+mode tnc
+.br
+#
+.br
+# If you selected digi, you must define a callsign. If you selected
+.br
+# tnc mode, the callsign is currently optional, but this may change
+.br
+# in the future! (2 calls if using dual port kiss)
+.br
+#
+.br
+# mycall vk5xxx-4
+.br
+# mycall2 vk5xxx-5
+.br
+#
+.br
+# In digi mode, you may use an alias. (2 for dual port)
+.br
+#
+.br
+# myalias svwdns
+.br
+# myalias2 svwdn2
+.br
+#
+.br
+# Send an ident every 540 seconds ...
+.br
+#
+.br
+# beacon after 540
+.br
+# btext ax25ip -- tncmode rob/vk5xxx -- Experimental AXIP gateway
+.br
+#
+.br
+# Serial port, or pipe connected to a kissattach in my case
+.br
+#
+.br
+device /dev/ttyp0
+.br
+#
+.br
+# Set the device speed
+.br
+#
+.br
+speed 9600
+.br
+#
+.br
+# loglevel 0 - no output
+.br
+# loglevel 1 - config info only
+.br
+# loglevel 2 - major events and errors
+.br
+# loglevel 3 - major events, errors, and AX25 frame trace
+.br
+# loglevel 4 - all events
+.br
+# log 0 for the moment, syslog not working yet ...
+.br
+#
+.br
+loglevel 4
+.br
+#
+.br
+# If we are in digi mode, we might have a real tnc here, so use param to
+.br
+# set the tnc parameters ...
+.br
+#
+.br
+# param 1 20
+.br
+#
+.br
+# Broadcast Address definition. Any of the addresses listed will be forwarded
+.br
+# to any of the routes flagged as broadcast capable routes.
+.br
+#
+.br
+broadcast QST-0 NODES-0
+.br
+#
+.br
+# ax.25 route definition, define as many as you need.
+.br
+# format is route (call/wildcard) (ip host at destination)
+.br
+# ssid of 0 routes all ssid's
+.br
+#
+.br
+# route <destcall> <destaddr> [flags]
+.br
+#
+.br
+# Valid flags are:
+.br
+# b - allow broadcasts to be transmitted via this route
+.br
+# d - this route is the default route
+.br
+#
+.br
+route vk2sut-0 44.136.8.68 b
+.br
+route vk5asf 44.136.188.221 b
+.br
+route vk2abc 44.1.1.1 d
+.br
+#
+.br
+#
+.br
+.LP
+More to come ...
+.SH FILES
+.LP
+/etc/ax25/ax25ipd.conf
+.SH "SEE ALSO"
+.BR ax25ipd (8).
diff --git a/ax25ipd/ax25ipd.h b/ax25ipd/ax25ipd.h
new file mode 100644
index 0000000..eeaf183
--- /dev/null
+++ b/ax25ipd/ax25ipd.h
@@ -0,0 +1,182 @@
+/* ax25ipd.h general configuration info
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ */
+
+/*
+ * Modifications added for dual port kiss TNC
+ * by Michael Durrant and D. Jeff Dionne Feb 4, 1995
+ */
+
+/*
+ * cleaned up and prototyped for inclusion into the standard linux ax25
+ * toolset in january 1997 by rob mayfield, vk5xxx/vk5zeu
+ */
+
+/*
+ * added route flags, it's a little ugly, but is extensible fairly easily.
+ * provided a mechanism for handling broadcast traffic
+ * Terry Dawson, VK2KTJ, July 1997.
+ */
+
+/* Define the current version number
+ *
+ * The first digit represents the major release (0 is a prototype release)
+ *
+ * The second represents major changes that might affect configuration
+ * file formats or compilation sequences, or anything that may make
+ * existing setups change.
+ *
+ * The last digit(s) marks simple bug fixes.
+ *
+ */
+
+#define VERS2 "Version 1.0.2"
+
+#define IPPROTO_AX25 93
+#define DEFAULT_UDP_PORT 10093
+
+/* local includes */
+#include "../pathnames.h"
+
+/* system includes */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <netdb.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <termio.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <netax25/daemon.h>
+
+int udp_mode; /* true if we need a UDP socket */
+int ip_mode; /* true if we need the raw IP socket */
+unsigned short my_udp; /* the UDP port to use (network byte order) */
+char ttydevice[128]; /* the tty device for serial comms */
+int ttyspeed; /* The baud rate on the tty device */
+unsigned char mycallsign[7]; /* My callsign, shifted ASCII with SSID */
+unsigned char mycallsign2[7]; /* My seconds port callsign, shifted ASCII with SSID */
+unsigned char myalias[7]; /* An alias to use */
+unsigned char myalias2[7]; /* An alias for second port */
+char bc_text[128]; /* The text for beacon messages */
+int bc_interval; /* The interval, in seconds, between beacons */
+int bc_every; /* true=every, false=after */
+int digi; /* True if we are connected to a TNC */
+int loglevel; /* Verbosity level */
+/* addition for dual port flag */
+int dual_port;
+
+struct {
+ int kiss_in; /* # packets received */
+ int kiss_toobig; /* packet too large */
+ int kiss_badtype; /* control byte non-zero */
+ int kiss_out; /* # packets sent */
+ int kiss_beacon_outs; /* # of beacons sent */
+ int kiss_tooshort; /* packet too short to be a valid frame */
+ int kiss_not_for_me; /* packet not for me (in digi mode) */
+ int kiss_i_am_dest; /* I am destination (in digi mode) */
+ int kiss_no_ip_addr; /* Couldn't find an IP addr for this call */
+ int udp_in; /* # packets received */
+ int udp_out; /* # packets sent */
+ int ip_in; /* # packets received */
+ int ip_out; /* # packets sent */
+ int ip_failed_crc; /* from ip, but failed CRC check */
+ int ip_tooshort; /* packet too short to be a valid frame */
+ int ip_not_for_me; /* packet not for me (in digi mode) */
+ int ip_i_am_dest; /* I am destination (in digi mode) */
+} stats;
+
+#define MAX_FRAME 2048
+
+#define LOGL1 if(loglevel>0)(void)printf
+#define LOGL2 if(loglevel>1)(void)printf
+#define LOGL3 if(loglevel>2)(void)printf
+#define LOGL4 if(loglevel>3)(void)printf
+
+#define AXRT_BCAST 1
+#define AXRT_DEFAULT 2
+
+/* start external prototypes */
+/* end external prototypes */
+
+/* kiss.c */
+void kiss_init(void);
+void assemble_kiss(unsigned char *, int);
+void send_kiss(unsigned char, unsigned char *, int);
+void param_add(int, int);
+void dump_params(void);
+void send_params(void);
+/* void do_beacon(void); not here it isnt !! xxx */
+
+/* routing.c */
+void route_init(void);
+void route_add(unsigned char *, unsigned char *, int, unsigned int);
+void bcast_add(unsigned char *);
+unsigned char *call_to_ip(unsigned char *);
+int is_call_bcast(unsigned char *);
+void send_broadcast(unsigned char *, int);
+void dump_routes(void);
+
+/* config.c */
+void config_init(void);
+void config_read(char *);
+int parse_line(char *);
+int a_to_call(char *, unsigned char *);
+char *call_to_a(unsigned char *);
+void dump_config(void);
+
+/* process.c */
+void process_init(void);
+void from_kiss(unsigned char *, int);
+void from_ip(unsigned char *, int);
+/* void do_broadcast(void); where did this go ?? xxx */
+void do_beacon(void);
+int addrmatch(unsigned char *, unsigned char *);
+unsigned char *next_addr(unsigned char *);
+void add_crc(unsigned char *, int);
+void dump_ax25frame(char *, unsigned char *, int);
+
+/* io.c */
+void io_init(void);
+void io_open(void);
+void io_start(void);
+void send_ip(unsigned char *, int, unsigned char *);
+void send_tty(unsigned char *, int);
+int io_error(int, unsigned char *, int, int, int);
+
+/* crc.c */
+unsigned short int compute_crc(unsigned char *, int);
+unsigned short int pppfcs(register unsigned short, register unsigned char *, register int);
+unsigned short int compute_crc(unsigned char *, int);
+int ok_crc(unsigned char *, int);
+
+/* ax25ipd.c */
+int main(int, char **);
+void greet_world(void);
+void do_stats(void);
+void hupper(int);
+void usr1_handler(int);
+void int_handler(int);
+void term_handler(int);
+
+/*
+ * end
+ */
diff --git a/ax25ipd/config.c b/ax25ipd/config.c
new file mode 100644
index 0000000..243b82c
--- /dev/null
+++ b/ax25ipd/config.c
@@ -0,0 +1,404 @@
+/* config.c config file manipulation routines
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ */
+
+/*
+ * Modifications made for dual port TNC's
+ * by Michael Durrant and D. Jeff Dionne February 4, 1995
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <memory.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "ax25ipd.h"
+
+/* Initialize the config table */
+void
+config_init()
+{
+ int i;
+
+ *ttydevice = '\0';
+ for(i=0;i<7;i++)mycallsign[i]='\0';
+ for(i=0;i<7;i++)myalias[i]='\0';
+ for(i=0;i<7;i++)mycallsign2[i]='\0';
+ for(i=0;i<7;i++)myalias2[i]='\0';
+ digi = 1;
+ ttyspeed = 9600;
+ loglevel = 0;
+ bc_interval = 0;
+ bc_text[0]='\0';
+ bc_every = 0;
+ my_udp = htons(0);
+ udp_mode = 0;
+ ip_mode = 0;
+ dual_port = 0;
+
+ stats.kiss_in = 0;
+ stats.kiss_toobig = 0;
+ stats.kiss_badtype = 0;
+ stats.kiss_tooshort = 0;
+ stats.kiss_not_for_me = 0;
+ stats.kiss_i_am_dest = 0;
+ stats.kiss_no_ip_addr = 0;
+ stats.kiss_out = 0;
+ stats.kiss_beacon_outs = 0;
+ stats.udp_in = 0;
+ stats.udp_out = 0;
+ stats.ip_in = 0;
+ stats.ip_out = 0;
+ stats.ip_failed_crc = 0;
+ stats.ip_tooshort = 0;
+ stats.ip_not_for_me = 0;
+ stats.ip_i_am_dest = 0;
+}
+
+/* Open and read the config file */
+
+void
+config_read(f)
+char *f;
+{
+ FILE *cf;
+ char buf[256], cbuf[256];
+ int errflag, e, lineno;
+ char *fname;
+
+ if (f) fname = f;
+ else fname = CONF_AX25IPD_FILE;
+
+ if((cf = fopen(fname,"r"))==NULL) {
+ fprintf(stderr,"Config file %s not found or could not be opened\n",fname);
+ exit(1);
+ }
+
+ errflag = 0;
+ lineno = 0;
+ while(fgets(buf, 255, cf)!=NULL) {
+ strcpy(cbuf, buf);
+ lineno++;
+ if((e = parse_line(buf)) < 0) {
+ fprintf(stderr,"Config error at line %d: ",lineno);
+ if(e==-1)fprintf(stderr,"Missing argument\n");
+ else if(e==-2)fprintf(stderr,"Bad callsign format\n");
+ else if(e==-3)fprintf(stderr,"Bad option - on/off\n");
+ else if(e==-4)fprintf(stderr,"Bad option - tnc/digi\n");
+ else if(e==-5)fprintf(stderr,"Host not known\n");
+ else if(e==-6)fprintf(stderr,"Unknown command\n");
+ else if(e==-7)fprintf(stderr,"Text string too long\n");
+ else if(e==-8)fprintf(stderr,"Bad option - every/after\n");
+ else if(e==-9)fprintf(stderr,"Bad option - ip/udp\n");
+ else fprintf(stderr,"Unknown error\n");
+ fprintf(stderr,"%s",cbuf);
+ errflag++;
+ }
+ }
+ if(errflag)exit(1);
+
+ if(strlen(ttydevice)==0) {
+ fprintf(stderr,"No device specified in config file\n");
+ exit(1);
+ }
+
+ if((udp_mode == 0) && (ip_mode == 0)) {
+ fprintf(stderr,"Must specify ip and/or udp sockets\n");
+ exit(1);
+ }
+
+ if(digi) {
+ if(mycallsign[0]=='\0') {
+ fprintf(stderr,"No mycall line in config file\n");
+ exit(1);
+ }
+ }
+ if((digi) && (dual_port)) {
+ if(mycallsign2[0]=='\0') {
+ fprintf(stderr,"No mycall2 line in config file\n");
+ exit(1);
+ }
+ }
+}
+
+/* Process each line from the config file. The return value is encoded. */
+int
+parse_line(buf)
+char *buf;
+{
+ char *p, *q;
+ unsigned char tcall[7], tip[4];
+ struct hostent *he;
+ int i,j, uport;
+ unsigned int flags;
+
+ p = strtok(buf, " \t\n\r");
+
+ if(p==NULL)return 0;
+ if(*p=='#')return 0;
+
+ if(strcmp(p,"mycall")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ if(a_to_call(q, mycallsign)!=0)return -2;
+ return 0;
+
+ } else if(strcmp(p,"mycall2")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ if(a_to_call(q, mycallsign2)!=0)return -2;
+ return 0;
+
+ } else if(strcmp(p,"myalias")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ if(a_to_call(q, myalias)!=0)return -2;
+ dual_port = 1;
+ if(mycallsign2[0]=='\0') {
+ dual_port = 0;
+ }
+ return 0;
+
+ } else if(strcmp(p,"myalias2")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ if(a_to_call(q, myalias2)!=0)return -2;
+ return 0;
+
+ } else if(strcmp(p,"device")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ strcpy(ttydevice, q);
+ return 0;
+
+ } else if(strcmp(p,"mode")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ if(strcmp(q,"digi")==0) digi = 1;
+ else if(strcmp(q,"tnc")==0) digi = 0;
+ else return -4;
+ return 0;
+
+ } else if(strcmp(p,"speed")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ ttyspeed = atoi(q);
+ return 0;
+
+ } else if(strcmp(p,"socket")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if (q==NULL)
+ return -1;
+ if (strcmp(q,"ip")==0) {
+ ip_mode = 1;
+ }
+ else if(strcmp(q,"udp")==0) {
+ udp_mode = 1;
+ my_udp = htons(DEFAULT_UDP_PORT);
+ q = strtok(NULL, " \t\n\r");
+ if (q!=NULL) {
+ i = atoi(q);
+ if (i>0)
+ my_udp = htons(i);
+ }
+ }
+ else
+ return -9;
+ return 0;
+
+ } else if(strcmp(p,"beacon")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if (q==NULL)
+ return -1;
+
+ if (strcmp(q,"every")==0)
+ bc_every = 1;
+ else if (strcmp(q,"after")==0)
+ bc_every = 0;
+ else
+ return -8;
+
+ q = strtok(NULL, " \t\n\r");
+ if (q==NULL)
+ return -1;
+ bc_interval = atoi(q);
+ return 0;
+
+/* This next one is a hack!!!!!! watch out!!!! */
+ } else if(strcmp(p,"btext")==0) {
+ q = p + strlen(p) + 1;
+ if(strlen(q) < 2) return -1; /* line ends with a \n */
+ if(strlen(q) > sizeof bc_text)return -7;
+ q[strlen(q)-1]='\0';
+ strcpy(bc_text, q);
+ return 0;
+
+ } else if(strcmp(p,"loglevel")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ loglevel = atoi(q);
+ return 0;
+
+ } else if(strcmp(p,"route")==0) {
+ uport = 0;
+ flags = 0;
+
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)
+ return -1;
+
+ if(a_to_call(q, tcall)!=0)
+ return -2;
+
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)
+ return -1;
+ he = gethostbyname(q);
+ if(he!=NULL) {
+ memcpy(tip, he->h_addr_list[0], 4);
+ } else { /* maybe user specified a numeric addr? */
+ j = inet_addr(q);
+ if(j==-1)
+ return -5; /* if -1, bad deal! */
+ memcpy(tip, (char *)&j, 4);
+ }
+
+ while((q = strtok(NULL, " \t\n\r"))!=NULL) {
+ if(strcmp(q,"udp")==0) {
+ uport = DEFAULT_UDP_PORT;
+ q = strtok(NULL, " \t\n\r");
+ if(q!=NULL) {
+ i = atoi(q);
+ if(i>0)
+ uport = i;
+ }
+ } else {
+ /* Test for broadcast flag */
+ if (strchr(q,'b')) {
+ flags|=AXRT_BCAST;
+ }
+
+ /* Test for Default flag */
+ if (strchr(q,'d')) {
+ flags|=AXRT_DEFAULT;
+ }
+ }
+ }
+ route_add(tip, tcall, uport, flags);
+ return 0;
+
+ } else if(strcmp(p,"broadcast")==0) {
+
+ while ((q = strtok(NULL, " \t\n\r"))!=NULL) {
+ if (a_to_call(q, tcall)!=0)
+ return -2;
+ bcast_add(tcall);
+ }
+ return 0;
+
+ } else if(strcmp(p,"param")==0) {
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ i = atoi(q);
+ q = strtok(NULL, " \t\n\r");
+ if(q==NULL)return -1;
+ j = atoi(q);
+ param_add(i,j);
+ return 0;
+ }
+ return -999;
+}
+
+/* Convert ascii callsign to internal format */
+int
+a_to_call(text, tcall)
+char *text;
+unsigned char *tcall;
+{
+ int i;
+ int ssid;
+ unsigned char c;
+
+ if(strlen(text)==0)return -1;
+
+ ssid = 0;
+ for(i=0;i<6;i++) {
+ tcall[i]=(' '<<1);
+ }
+ tcall[6] = '\0';
+
+ for(i=0;i<strlen(text);i++) {
+ c = text[i];
+ if(c=='-') {
+ ssid = atoi(&text[i+1]);
+ if(ssid>15)return -1;
+ tcall[6] = (ssid<<1);
+ return 0;
+ }
+ if(islower(c))c = toupper(c);
+ if(i>5)return -1;
+ tcall[i]=(c<<1);
+ }
+ return 0;
+}
+
+/* Convert internal callsign to printable format */
+char *
+call_to_a(tcall)
+unsigned char *tcall;
+{
+ int i;
+ int ssid;
+ char *tptr;
+ static char t[10];
+
+ for(i=0,tptr=t;i<6;i++) {
+ if(tcall[i]==(' '<<1))break;
+ *tptr = tcall[i]>>1;
+ tptr++;
+ }
+
+ ssid = (tcall[6]>>1)&0x0f;
+ if(ssid>0) {
+ *tptr = '-';
+ tptr++;
+ if(ssid>9) {
+ *tptr = '1';
+ tptr++;
+ ssid -= 10;
+ }
+ *tptr = '0' + ssid;
+ tptr++;
+ }
+
+ *tptr = '\0';
+ return &t[0];
+}
+
+/* print the configuration data out */
+void
+dump_config()
+{
+ LOGL1("\nCurrent configuration:\n");
+ if(ip_mode) LOGL1(" socket ip\n");
+ if(udp_mode)LOGL1(" socket udp on port %d\n", ntohs(my_udp));
+ LOGL1(" mode %s\n", digi ? "digi" : "tnc");
+ LOGL1(" device %s\n", ttydevice);
+ LOGL1(" speed %d\n", ttyspeed);
+ if(digi)LOGL1(" mycall %s\n", call_to_a(mycallsign));
+ if(digi && myalias[0])LOGL1(" myalias %s\n", call_to_a(myalias));
+ if(bc_interval>0) {
+ LOGL1(" beacon %s %d\n", bc_every ? "every" : "after", bc_interval);
+ LOGL1(" btext %s\n", bc_text);
+ }
+ LOGL1(" loglevel %d\n", loglevel);
+ (void)fflush(stdout);
+}
diff --git a/ax25ipd/crc.c b/ax25ipd/crc.c
new file mode 100644
index 0000000..ff07195
--- /dev/null
+++ b/ax25ipd/crc.c
@@ -0,0 +1,171 @@
+/* crc.c Computations involving CRCs */
+
+#include "ax25ipd.h"
+/*
+ **********************************************************************
+ * The following code was taken from Appendix B of RFC 1171
+ * (Point-to-Point Protocol)
+ *
+ * The RFC credits the following sources for this implementation:
+ *
+ * Perez, "Byte-wise CRC Calculations", IEEE Micro, June, 1983.
+ *
+ * Morse, G., "Calculating CRC's by Bits and Bytes", Byte,
+ * September 1986.
+ *
+ * LeVan, J., "A Fast CRC", Byte, November 1987.
+ *
+ *
+ * The HDLC polynomial: x**0 + x**5 + x**12 + x**16
+ */
+
+/*
+ * u16 represents an unsigned 16-bit number. Adjust the typedef for
+ * your hardware.
+ */
+typedef unsigned short u16;
+
+
+/*
+ * FCS lookup table as calculated by the table generator in section 2.
+ */
+static u16 fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPPINITFCS 0xffff /* Initial FCS value */
+#define PPPGOODFCS 0xf0b8 /* Good final FCS value */
+
+/*
+ * Calculate a new fcs given the current fcs and the new data.
+ */
+u16 pppfcs(fcs, cp, len)
+ register u16 fcs;
+ register unsigned char *cp;
+ register int len;
+{
+/* ASSERT(sizeof (u16) == 2); */
+/* ASSERT(((u16) -1) > 0); */
+ while (len--)
+ fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+
+ return (fcs);
+}
+
+/*
+ * End code from Appendix B of RFC 1171
+ **********************************************************************
+ */
+
+/*
+ * The following routines are simply convenience routines...
+ * I'll merge them into the mainline code when suitably debugged
+ */
+
+/* Return the computed CRC */
+unsigned short int
+compute_crc(buf, l)
+unsigned char *buf;
+int l;
+{
+ int fcs;
+
+ fcs = PPPINITFCS;
+ fcs = pppfcs(fcs, buf, l);
+ fcs ^= 0xffff;
+ return fcs;
+}
+
+/* Return true if the CRC is correct */
+int
+ok_crc(buf, l)
+unsigned char *buf;
+int l;
+{
+ int fcs;
+
+ fcs = PPPINITFCS;
+ fcs = pppfcs(fcs, buf, l);
+ return (fcs == PPPGOODFCS);
+}
+
+/*
+ * A test routine to make sure the CRC is working right on your hardware.
+ * cc -DTEST crc.c
+ *
+ */
+
+#ifdef TEST
+void
+main()
+{
+ unsigned char buf[258];
+ int l, i;
+ unsigned short int f;
+
+ l = 256;
+ for(i=0;i<l;i++){
+ buf[i]=i;
+ }
+
+ f = compute_crc(buf,l);
+ printf("computed crc=0x%04x\n",f);
+
+ buf[l]=(f&0xff);
+ buf[l+1]=(f>>8);
+ printf("crc should be good... ");
+ i = ok_crc(buf, l+2);
+ if(i)printf("CRC declared OK\n");
+ else printf("CRC declared bad\n");
+
+ buf[l+1]=(f&0xff);
+ buf[l]=(f>>8);
+ printf("reversed the CRC byte order... CRC should be bad...");
+ i = ok_crc(buf, l+2);
+ if(i)printf("CRC declared OK\n");
+ else printf("CRC declared bad\n");
+
+ printf("changed the frame length... CRC should be bad...");
+ i = ok_crc(buf, l+1);
+ if(i)printf("CRC declared OK\n");
+ else printf("CRC declared bad\n");
+
+ buf[0]-=1;
+ printf("corrupted the data... CRC should be bad...");
+ i = ok_crc(buf, l+2);
+ if(i)printf("CRC declared OK\n");
+ else printf("CRC declared bad\n");
+
+}
+#endif
diff --git a/ax25ipd/io.c b/ax25ipd/io.c
new file mode 100644
index 0000000..88a4923
--- /dev/null
+++ b/ax25ipd/io.c
@@ -0,0 +1,574 @@
+/* io.c All base I/O routines live here
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ * This is the only module that knows about base level UNIX/SunOS I/O
+ * This is also the key dispatching module, so it knows about a lot more
+ * than just I/O stuff.
+ */
+
+#undef USE_ICMP /* not implemented yet, sorry */
+
+#include "ax25ipd.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef USE_ICMP
+#include <netinet/ip_icmp.h>
+#endif
+#include <netdb.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __bsdi__
+#define USE_TERMIOS
+#endif
+
+#ifndef USE_TERMIOS
+#ifndef USE_TERMIO
+#define USE_SGTTY
+#endif
+#endif
+
+#ifdef USE_TERMIOS
+#include <sys/termios.h>
+struct termios nterm;
+#endif
+
+#ifdef USE_TERMIO
+#include <termio.h>
+struct termio nterm;
+#endif
+
+#ifdef USE_SGTTY
+#include <sys/ioctl.h>
+struct sgttyb nterm;
+#endif
+
+int ttyfd = -1;
+int udpsock = -1;
+int sock = -1;
+#ifdef USE_ICMP
+int icmpsock = -1;
+#endif
+struct sockaddr_in udpbind;
+struct sockaddr_in to;
+struct sockaddr_in from;
+int fromlen;
+
+time_t last_bc_time;
+
+/*
+ * I/O modes for the io_error routine
+ */
+#define READ_MSG 0x00
+#define SEND_MSG 0x01
+
+#define IP_MODE 0x10
+#define UDP_MODE 0x20
+#define TTY_MODE 0x30
+#ifdef USE_ICMP
+#define ICMP_MODE 0x40
+#endif
+
+#ifndef FNDELAY
+#define FNDELAY O_NDELAY
+#endif
+
+/*
+ * Initialize the io variables
+ */
+
+void
+io_init()
+{
+
+/*
+ * Close the file descriptors if they are open. The idea is that we
+ * will be able to support a re-initialization if sent a SIGHUP.
+ */
+
+ if(ttyfd>=0){
+ close(ttyfd);
+ ttyfd = -1;
+ }
+
+ if(sock>=0){
+ close(sock);
+ sock = -1;
+ }
+
+ if(udpsock>=0){
+ close(udpsock);
+ udpsock = -1;
+ }
+
+#ifdef USE_ICMP
+ if(icmpsock>=0){
+ close(icmpsock);
+ icmpsock = -1;
+ }
+#endif
+
+/*
+ * The bzero is not strictly required - it simply zeros out the
+ * address structure. Since both to and from are static, they are
+ * already clear.
+ */
+ bzero( (char *)&to, sizeof(struct sockaddr) );
+ to.sin_family = AF_INET;
+
+ bzero( (char *)&from, sizeof(struct sockaddr) );
+ from.sin_family = AF_INET;
+
+ bzero( (char *)&udpbind, sizeof(struct sockaddr) );
+ udpbind.sin_family = AF_INET;
+}
+
+/*
+ * open and initialize the IO interfaces
+ */
+
+void io_open()
+{
+ int baudrate;
+
+ if(ip_mode){
+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_AX25);
+ if (sock<0) {
+ perror("opening raw socket");
+ exit(1);
+ }
+ if (fcntl(sock, F_SETFL, FNDELAY) < 0) {
+ perror("setting non-blocking I/O on raw socket");
+ exit(1);
+ }
+
+#ifdef USE_ICMP
+ icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (icmpsock<0) {
+ perror("opening raw ICMP socket");
+ exit(1);
+ }
+ if (fcntl(icmpsock, F_SETFL, FNDELAY) < 0) {
+ perror("setting non-blocking I/O on ICMP socket");
+ exit(1);
+ }
+#endif
+ }
+
+ if(udp_mode){
+ udpsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (udpsock<0) {
+ perror("opening udp socket");
+ exit(1);
+ }
+ if (fcntl(udpsock, F_SETFL, FNDELAY) < 0) {
+ perror("setting non-blocking I/O on UDP socket");
+ exit(1);
+ }
+/*
+ * Ok, the udp socket is open. Now express our interest in receiving
+ * data destined for a particular socket.
+ */
+ udpbind.sin_addr.s_addr = INADDR_ANY;
+ udpbind.sin_port = my_udp;
+ if(bind(udpsock,(struct sockaddr *)&udpbind,sizeof udpbind)<0){
+ perror("binding udp socket");
+ exit(1);
+ }
+ }
+
+ ttyfd = open(ttydevice, O_RDWR, 0);
+ if (ttyfd<0) {
+ perror("opening tty device");
+ exit(1);
+ }
+ if (fcntl(ttyfd, F_SETFL, FNDELAY) < 0) {
+ perror("setting non-blocking I/O on tty device");
+ exit(1);
+ }
+
+#ifdef USE_TERMIOS
+ if(ioctl(ttyfd, TCGETS, &nterm)<0){
+#endif
+#ifdef USE_TERMIO
+ if(ioctl(ttyfd, TCGETA, &nterm)<0){
+#endif
+#ifdef USE_SGTTY
+ if(ioctl(ttyfd, TIOCGETP, &nterm)<0){
+#endif
+ perror("fetching tty device parameters");
+ exit(1);
+ }
+
+ if(ttyspeed==50)baudrate=B50;
+ else if(ttyspeed==50)baudrate=B50;
+ else if(ttyspeed==75)baudrate=B75;
+ else if(ttyspeed==110)baudrate=B110;
+ else if(ttyspeed==134)baudrate=B134;
+ else if(ttyspeed==150)baudrate=B150;
+ else if(ttyspeed==200)baudrate=B200;
+ else if(ttyspeed==300)baudrate=B300;
+ else if(ttyspeed==600)baudrate=B600;
+ else if(ttyspeed==1200)baudrate=B1200;
+ else if(ttyspeed==1800)baudrate=B1800;
+ else if(ttyspeed==2400)baudrate=B2400;
+ else if(ttyspeed==4800)baudrate=B4800;
+ else if(ttyspeed==9600)baudrate=B9600;
+#ifdef B19200
+ else if(ttyspeed==19200)baudrate=B19200;
+#else
+#ifdef EXTA
+ else if(ttyspeed==19200)baudrate=EXTA;
+#endif
+#endif
+#ifdef B38400
+ else if(ttyspeed==38400)baudrate=B38400;
+#else
+#ifdef EXTB
+ else if(ttyspeed==38400)baudrate=EXTB;
+#endif
+#endif
+ else baudrate = B9600;
+
+#ifdef USE_SGTTY
+ nterm.sg_flags = (RAW | ANYP);
+ nterm.sg_ispeed = baudrate;
+ nterm.sg_ospeed = baudrate;
+#else
+ nterm.c_iflag = 0;
+ nterm.c_oflag = 0;
+ nterm.c_cflag = baudrate | CS8 | CREAD | CLOCAL;
+ nterm.c_lflag = 0;
+ nterm.c_cc[VMIN] = 0;
+ nterm.c_cc[VTIME] = 0;
+#endif
+
+#ifdef USE_TERMIOS
+ if(ioctl(ttyfd, TCSETS, &nterm)<0){
+#endif
+#ifdef USE_TERMIO
+ if(ioctl(ttyfd, TCSETA, &nterm)<0){
+#endif
+#ifdef USE_SGTTY
+ if(ioctl(ttyfd, TIOCSETP, &nterm)<0){
+#endif
+ perror("setting tty device parameters");
+ exit(1);
+ }
+
+ if(digi)send_params();
+
+ last_bc_time = 0; /* force immediate id */
+}
+
+/*
+ * Start up and run the I/O mechanisms.
+ * run in a loop, using the select call to handle input.
+ */
+
+void
+io_start()
+{
+ int n, nb, hdr_len;
+ fd_set readfds;
+ unsigned char buf[MAX_FRAME];
+ struct timeval wait;
+ struct iphdr *ipptr;
+ time_t now;
+
+ for(;;){
+
+ if((bc_interval>0)&&digi){
+ now = time(NULL);
+ if (last_bc_time + bc_interval < now){
+ last_bc_time = now;
+ LOGL4("iostart: BEACON\n");
+ do_beacon();
+ }
+ }
+
+ wait.tv_sec = 10; /* lets us keep the beacon going */
+ wait.tv_usec = 0;
+
+ FD_ZERO(&readfds);
+
+ FD_SET(ttyfd, &readfds);
+
+ if(ip_mode){
+ FD_SET(sock, &readfds);
+#ifdef USE_ICMP
+ FD_SET(icmpsock, &readfds);
+#endif
+ }
+
+ if(udp_mode){
+ FD_SET(udpsock, &readfds);
+ }
+
+ nb = select(FD_SETSIZE,&readfds,(fd_set *)0,(fd_set *)0,&wait);
+
+ if(nb < 0){
+ if(errno == EINTR)continue; /* Ignore */
+ perror("select");
+ exit(1);
+ }
+
+ if(nb == 0){
+ fflush(stdout);
+ fflush(stderr);
+ /* just so we go back to the top of the loop! */
+ continue;
+ }
+
+ if(FD_ISSET(ttyfd, &readfds)){
+ do {
+ n = read(ttyfd, buf, MAX_FRAME);
+ } while(io_error(n, buf, n, READ_MSG, TTY_MODE));
+ LOGL4("ttydata l=%d\n",n);
+ if(n>0)assemble_kiss(buf,n);
+/*
+ * If we are in "beacon after" mode, reset the "last_bc_time" each time
+ * we hear something on the channel.
+ */
+ if(!bc_every)last_bc_time = time(NULL);
+ }
+
+ if(udp_mode){
+ if(FD_ISSET(udpsock, &readfds)){
+ do {
+ fromlen = sizeof from;
+ n = recvfrom(udpsock, buf, MAX_FRAME, 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while(io_error(n, buf, n, READ_MSG, UDP_MODE));
+ LOGL4("udpdata from=%s port=%d l=%d\n",
+ (char *)inet_ntoa(from.sin_addr),
+ ntohs(from.sin_port), n);
+ stats.udp_in++;
+ if(n>0)from_ip(buf, n);
+ }
+ } /* if udp_mode */
+
+ if(ip_mode){
+ if(FD_ISSET(sock, &readfds)){
+ do{
+ fromlen = sizeof from;
+ n = recvfrom(sock, buf, MAX_FRAME, 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while(io_error(n, buf, n, READ_MSG, IP_MODE));
+ ipptr = (struct iphdr *)buf;
+ hdr_len = 4 * ipptr->ihl;
+ LOGL4("ipdata from=%s l=%d, hl=%d\n",
+ (char *)inet_ntoa(from.sin_addr),
+ n, hdr_len);
+ stats.ip_in++;
+ if(n>hdr_len)from_ip(buf+hdr_len, n-hdr_len);
+ }
+
+#ifdef USE_ICMP
+ if(FD_ISSET(icmpsock, &readfds)){
+ do {
+ fromlen = sizeof from;
+ n = recvfrom(icmpsock, buf, MAX_FRAME, 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while(io_error(n, buf, n, READ_MSG, ICMP_MODE));
+ ipptr = (struct iphdr *)buf;
+ hdr_len = 4 * ipptr->ihl;
+ LOGL4("icmpdata from=%s l=%d, hl=%d\n",
+ (char *)inet_ntoa(from.sin_addr),
+ n, hdr_len);
+ }
+#endif
+ } /* if ip_mode */
+
+ } /* for forever */
+}
+
+/* Send an IP frame */
+
+void
+send_ip(buf, l, targetip)
+unsigned char *buf;
+int l;
+unsigned char *targetip;
+{
+ int n;
+
+ if(l<=0)return;
+ memcpy((char *)&to.sin_addr, targetip, 4);
+ memcpy((char *)&to.sin_port, &targetip[4], 2);
+ LOGL4("sendipdata to=%s %s %d l=%d\n",
+ (char *)inet_ntoa(to.sin_addr),
+ to.sin_port ? "udp" : "ip",
+ ntohs(to.sin_port), l);
+ if(to.sin_port){
+ if(udp_mode){
+ stats.udp_out++;
+ do {
+ n = sendto(udpsock, buf, l, 0,
+ (struct sockaddr *)&to, sizeof to);
+ } while(io_error(n, buf, l, SEND_MSG, UDP_MODE));
+ }
+ } else {
+ if(ip_mode){
+ stats.ip_out++;
+ do {
+ n = sendto(sock, buf, l, 0,
+ (struct sockaddr *)&to, sizeof to);
+ } while(io_error(n, buf, l, SEND_MSG, IP_MODE));
+ }
+ }
+}
+
+/* Send a kiss frame */
+
+void
+send_tty(buf, l)
+unsigned char *buf;
+int l;
+{
+ int n;
+ unsigned char *p;
+ int nc;
+
+ if(l<=0)return;
+ LOGL4("sendttydata l=%d\tsent: ",l);
+ stats.kiss_out++;
+
+ p = buf;
+ nc = l;
+ n = 0;
+
+/*
+ * we have to loop around here because each call to write may write a few
+ * characters. So we simply increment the buffer each time around. If
+ * we ever write no characters, we should get an error code, and io_error
+ * will sleep for a fraction of a second. Note that we are keyed to
+ * the BSD 4.2 behaviour... the Sys 5 non-blocking I/O may or may not work
+ * in this loop. We may detect system 5 behaviour (this would result from
+ * compile-time options) by having io_error barf when it detects an EAGAIN
+ * error code.
+ */
+ do {
+ if((n>0)&&(n<nc)) { /* did we put only write a bit? */
+ p += n; /* point to the new data */
+ nc -= n; /* drop the length */
+ }
+ n = write(ttyfd, p, nc);
+ if(n>0){
+ if(n!=nc){
+ LOGL4("%d ",n); /* no-one said loglevel 4 */
+ } else {
+ LOGL4("%d\n",n); /* was efficient!!! */
+ }
+ }
+ } while( ((n>0)&&(n<nc)) || (io_error(n, p, nc, SEND_MSG, TTY_MODE)));
+}
+
+/* process an I/O error; return true if a retry is needed */
+int
+io_error(oops, buf, bufsize, dir, mode)
+int oops; /* the error flag; < 0 indicates a problem */
+unsigned char *buf; /* the data in question */
+int bufsize; /* the size of the data buffer */
+int dir; /* the direction; input or output */
+int mode; /* the fd on which we got the error */
+{
+
+ if(oops >= 0) return 0; /* do we have an error ? */
+
+#ifdef EAGAIN
+ if(errno == EAGAIN){
+ perror("System 5 I/O error!");
+ fprintf(stderr,"A System 5 style I/O error was detected. This program requires BSD 4.2\n");
+ fprintf(stderr,"behaviour. This is probably a result of compile-time environment.\n");
+ exit(3);
+ }
+#endif
+
+ if(dir == READ_MSG){
+ if(errno == EINTR) return 0; /* never retry read */
+ if(errno == EWOULDBLOCK){
+ LOGL4("READ would block (?!), sleeping and retrying!\n");
+ usleep(100000); /* sleep a bit */
+ return 1; /* and retry */
+ }
+ if(mode == IP_MODE){
+ perror("reading from raw ip socket");
+ exit(2);
+ } else if(mode == UDP_MODE){
+ perror("reading from udp socket");
+ exit(2);
+ } else if(mode == TTY_MODE){
+ perror("reading from tty device");
+ exit(2);
+ } else {
+ perror("reading from unknown I/O");
+ exit(2);
+ }
+ } else if(dir == SEND_MSG){
+ if(errno == EINTR) return 1; /* always retry on writes */
+ if(mode == IP_MODE){
+ if(errno == EMSGSIZE){ /* msg too big, drop it */
+ perror("message dropped on raw ip socket");
+ fprintf(stderr,"message was %d bytes long.\n",bufsize);
+ return 0;
+ }
+ if(errno == ENOBUFS){ /* congestion; sleep + retry */
+ LOGL4("send congestion on raw ip, sleeping and retrying!\n");
+ usleep(100000);
+ return 1;
+ }
+ if(errno == EWOULDBLOCK){
+ LOGL4("send on raw ip would block, sleeping and retrying!\n");
+ usleep(100000); /* sleep a bit */
+ return 1; /* and retry */
+ }
+ perror("writing to raw ip socket");
+ exit(2);
+ } else if(mode == UDP_MODE){
+ if(errno == EMSGSIZE){ /* msg too big, drop it */
+ perror("message dropped on udp socket");
+ fprintf(stderr,"message was %d bytes long.\n",bufsize);
+ return 0;
+ }
+ if(errno == ENOBUFS){ /* congestion; sleep + retry */
+ LOGL4("send congestion on udp, sleeping and retrying!\n");
+ usleep(100000);
+ return 1;
+ }
+ if(errno == EWOULDBLOCK){
+ LOGL4("send on udp would block, sleeping and retrying!\n");
+ usleep(100000); /* sleep a bit */
+ return 1; /* and retry */
+ }
+ perror("writing to udp socket");
+ exit(2);
+ } else if(mode == TTY_MODE){
+ if(errno == EWOULDBLOCK){
+ LOGL4("write to tty would block, sleeping and retrying!\n");
+ usleep(100000); /* sleep a bit */
+ return 1; /* and retry */
+ }
+ perror("writing to tty device");
+ exit(2);
+ } else {
+ perror("writing to unknown I/O");
+ exit(2);
+ }
+ } else {
+ perror("Unknown direction and I/O");
+ exit(2);
+ }
+ return 0;
+}
diff --git a/ax25ipd/kiss.c b/ax25ipd/kiss.c
new file mode 100644
index 0000000..6042cf0
--- /dev/null
+++ b/ax25ipd/kiss.c
@@ -0,0 +1,201 @@
+/* kiss.c KISS assembly and byte-stuffing stuff
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ * This is the only module that knows about the internal structure of
+ * KISS frames.
+ */
+
+/*
+ * dual port changes Feb 95 ve3pnx & ve3djf
+ */
+
+#include <stdio.h>
+#include "ax25ipd.h"
+
+#define FEND 0xc0
+#define FESC 0xdb
+#define TFEND 0xdc
+#define TFESC 0xdd
+
+unsigned char iframe[MAX_FRAME];
+unsigned char *ifptr;
+int ifcount;
+int iescaped;
+
+unsigned char oframe[MAX_FRAME];
+unsigned char *ofptr;
+int ofcount;
+
+#define PTABLE_SIZE 10
+
+struct param_table_entry {
+ unsigned char parameter;
+ unsigned char value;
+} param_tbl[PTABLE_SIZE];
+
+int param_tbl_top;
+
+
+/*
+ * Initialize the KISS variables
+ */
+
+void
+kiss_init()
+{
+ ifptr = iframe;
+ ifcount = 0;
+ iescaped = 0;
+ ofptr = oframe;
+ ofcount = 0;
+ param_tbl_top = 0;
+}
+
+/*
+ * Assemble a kiss frame from random hunks of incoming data
+ * Calls the "from_kiss" routine with the kiss frame when a
+ * frame has been assembled.
+ */
+
+void
+assemble_kiss(buf, l)
+unsigned char *buf;
+int l;
+{
+ int i;
+ unsigned char c;
+
+ for(i=0;i<l;i++,buf++){
+ c = *buf;
+ if(c==FEND){
+ if(ifcount>0){
+ /* Make sure that the control byte is zero */
+ if(*iframe=='\0' || *iframe==0x10) {
+ /* Room for CRC in buffer? */
+ if(ifcount < (MAX_FRAME - 2)) {
+ stats.kiss_in++;
+ from_kiss(iframe+1,ifcount-1);
+ } else {
+ stats.kiss_toobig++;
+ LOGL2("assemble_kiss: dumped - frame too large\n");
+ }
+ } else {
+ stats.kiss_badtype++;
+ LOGL2("assemble_kiss: dumped - control byte non-zero\n");
+ }
+ }
+ ifcount = 0;
+ iescaped = 0;
+ ifptr = iframe;
+ continue;
+ }
+ if(c==FESC){
+ iescaped=1;
+ continue;
+ }
+ if(iescaped){
+ if(c==TFEND)c = FEND;
+ if(c==TFESC)c = FESC;
+ iescaped = 0;
+ }
+ if(ifcount < MAX_FRAME){
+ *ifptr = c;
+ ifptr++;
+ ifcount++;
+ }
+ } /* for every character in the buffer */
+}
+
+/* convert a standard AX25 frame into a kiss frame */
+void
+send_kiss(type, buf, l)
+unsigned char type;
+unsigned char *buf;
+int l;
+{
+#define KISSEMIT(x) if(ofcount<MAX_FRAME){*ofptr=(x);ofptr++;ofcount++;}
+
+ int i;
+
+ ofptr = oframe;
+ ofcount = 0;
+
+ KISSEMIT(FEND);
+
+ if(type==FEND){
+ KISSEMIT(FESC);
+ KISSEMIT(TFEND);
+ }else if (type==FESC){
+ KISSEMIT(FESC);
+ KISSEMIT(TFESC);
+ }else {
+ KISSEMIT(type);
+ }
+
+ for(i=0;i<l;i++,buf++){
+ if(*buf==FEND){
+ KISSEMIT(FESC);
+ KISSEMIT(TFEND);
+ }else if (*buf==FESC){
+ KISSEMIT(FESC);
+ KISSEMIT(TFESC);
+ }else {
+ KISSEMIT(*buf);
+ }
+ } /* for each character in the incoming AX25 frame */
+
+ KISSEMIT(FEND);
+
+ send_tty(oframe, ofcount);
+}
+
+/* Add an entry to the parameter table */
+void
+param_add(p, v)
+int p;
+int v;
+{
+ if(param_tbl_top >= PTABLE_SIZE){
+ fprintf(stderr,"param table is full; entry ignored.\n");
+ }
+ param_tbl[param_tbl_top].parameter = p&0xff;
+ param_tbl[param_tbl_top].value = v&0xff;
+ LOGL4("added param: %d\t%d\n",
+ param_tbl[param_tbl_top].parameter,
+ param_tbl[param_tbl_top].value);
+ param_tbl_top++;
+ return;
+}
+
+/* dump the contents of the parameter table */
+void
+dump_params()
+{
+ int i;
+
+ LOGL1("\n%d parameters\n",param_tbl_top);
+ for(i=0;i<param_tbl_top;i++){
+ LOGL1(" %d\t%d\n",
+ param_tbl[i].parameter,
+ param_tbl[i].value);
+ }
+ fflush(stdout);
+}
+
+/* send the parameters to the TNC */
+void
+send_params()
+{
+ int i;
+ unsigned char p, v;
+
+ for(i=0;i<param_tbl_top;i++){
+ p = param_tbl[i].parameter;
+ v = param_tbl[i].value;
+ send_kiss(p, &v, 1);
+ LOGL2("send_params: param %d %d\n",p,v);
+ }
+}
diff --git a/ax25ipd/process.c b/ax25ipd/process.c
new file mode 100644
index 0000000..20bae7f
--- /dev/null
+++ b/ax25ipd/process.c
@@ -0,0 +1,338 @@
+/* process.c Handle processing and routing of AX25 frames
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ * This is the only module that knows about the internal structure of
+ * AX25 frames.
+ */
+
+/*
+ * Dual port additions by M.Durrant and D.J.Dionne Feb 4, 1995
+ */
+
+#include "ax25ipd.h"
+#include <stdio.h>
+/* if dual port the upper nibble will have a value of 1 (not 0) */
+#define FROM_PORT2(p) (((*(p+1))&0x10)!=0)
+#define FOR_PORT2(p) (addrmatch(p,mycallsign2) || addrmatch(p,myalias2))
+/* ve3djf and ve3pnx addition above */
+#define IS_LAST(p) (((*(p+6))&0x01)!=0)
+#define NOT_LAST(p) (((*(p+6))&0x01)==0)
+#define REPEATED(p) (((*(p+6))&0x80)!=0)
+#define NOTREPEATED(p) (((*(p+6))&0x80)==0)
+#define IS_ME(p) (addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) )
+#define NOT_ME(p) (!(addrmatch(p,mycallsign) || addrmatch(p,myalias) || addrmatch(p,mycallsign2) || addrmatch(p,myalias2) ) )
+#define ARE_DIGIS(f) (((*(f+13))&0x01)==0)
+#define NO_DIGIS(f) (((*(f+13))&0x01)!=0)
+#define SETREPEATED(p) (*(p+6))|=0x80
+#define SETLAST(p) (*(p+6))|=0x01
+
+unsigned char bcbuf[256]; /* Must be larger than bc_text!!! */
+int bclen; /* The size of bcbuf */
+
+/*
+ * Initialize the process variables
+ */
+
+void
+process_init()
+{
+ bclen = -1; /* flag that we need to rebuild the bctext */
+}
+
+/*
+ * handle a frame given us by the kiss routines. The buf variable is
+ * a pointer to an AX25 frame. Note that the AX25 frame from kiss does
+ * not include the CRC bytes. These are computed by this routine, and
+ * it is expected that the buffer we have has room for the CRC bytes.
+ * We will either dump this frame, or send it via the IP interface.
+ *
+ * If we are in digi mode, we validate in several ways:
+ * a) we must be the next digi in line to pick up the packet
+ * b) the next site to get the packet (the next listed digi, or
+ * the destination if we are the last digi) must be known to
+ * us via the route table.
+ * If we pass validation, we then set the digipeated bit for our entry
+ * in the packet, compute the CRC, and send the packet to the IP
+ * interface.
+ *
+ * If we are in tnc mode, we have less work to do.
+ * a) the next site to get the packet (the next listed digi, or
+ * the destination) must be known to us via the route table.
+ * If we pass validation, we compute the CRC, and send the packet to
+ * the IP interface.
+ */
+
+void
+from_kiss(buf, l)
+unsigned char *buf;
+int l;
+{
+ unsigned char *a, *ipaddr;
+
+ if (l<15) {
+ LOGL2("from_kiss: dumped - length wrong!\n");
+ stats.kiss_tooshort++;
+ return;
+ }
+
+ if (loglevel>2)
+ dump_ax25frame("from_kiss: ", buf, l);
+
+ if(digi) { /* if we are in digi mode */
+ a = next_addr(buf);
+ if(NOT_ME(a)){
+ stats.kiss_not_for_me++;
+ LOGL4("from_kiss: (digi) dumped - not for me\n");
+ return;
+ }
+ if (a==buf) { /* must be a digi */
+ stats.kiss_i_am_dest++;
+ LOGL2("from_kiss: (digi) dumped - I am destination!\n");
+ return;
+ }
+ SETREPEATED(a);
+ a = next_addr(buf); /* find who gets it after us */
+ } else { /* must be tnc mode */
+ a = next_addr(buf);
+#ifdef TNC_FILTER
+ if (IS_ME(a)) {
+ LOGL2("from_kiss: (tnc) dumped - addressed to self!\n");
+ return;
+ }
+#endif
+ } /* end of tnc mode */
+
+ /* Lookup the IP address for this route */
+ ipaddr = call_to_ip(a);
+
+ if (ipaddr==NULL) {
+ if (is_call_bcast(a)) {
+ /* Warning - assuming buffer has room for 2 bytes */
+ add_crc(buf, l); l+=2;
+ send_broadcast(buf, l);
+ } else {
+ stats.kiss_no_ip_addr++;
+ LOGL2("from_kiss: dumped - cannot figure out where to send this!\n");
+ }
+ return;
+ } else {
+ /* Warning - assuming buffer has room for 2 bytes */
+ add_crc(buf, l); l+=2;
+ send_ip(buf, l, ipaddr);
+ }
+}
+
+/*
+ * handle a frame given us by the IP routines. The buf variable is
+ * a pointer to an AX25 frame.
+ * Note that the frame includes the CRC bytes, which we dump ASAP.
+ * We will either dump this frame, or send it via the KISS interface.
+ *
+ * If we are in digi mode, we only validate that:
+ * a) we must be the next digi in line to pick up the packet
+ * If we pass validation, we then set the digipeated bit for our entry
+ * in the packet, and send the packet to the KISS send routine.
+ *
+ * If we are in tnc mode, we validate pretty well nothing, just like a
+ * real TNC... #define FILTER_TNC will change this.
+ * We simply send the packet to the KISS send routine.
+ */
+
+void
+from_ip(buf, l)
+unsigned char *buf;
+int l;
+{
+ int port = 0;
+ unsigned char *a;
+
+ if(!ok_crc(buf, l)){
+ stats.ip_failed_crc++;
+ LOGL2("from_ip: dumped - CRC incorrect!\n");
+ return;
+ }
+ l = l - 2; /* dump the blasted CRC */
+
+ if(l<15){
+ stats.ip_tooshort++;
+ LOGL2("from_ip: dumped - length wrong!\n");
+ return;
+ }
+
+ if(loglevel>2)dump_ax25frame("from_ip: ", buf, l);
+
+ if(digi){ /* if we are in digi mode */
+ a = next_addr(buf);
+ if(NOT_ME(a)){
+ stats.ip_not_for_me++;
+ LOGL2("from_ip: (digi) dumped - not for me!\n");
+ return;
+ }
+ if(a==buf){ /* must be a digi */
+ stats.ip_i_am_dest++;
+ LOGL2("from_ip: (digi) dumped - I am destination!\n");
+ return;
+ }
+ if(dual_port == 1 && FOR_PORT2(a)){
+ port = 0x10;
+ }
+ SETREPEATED(a);
+ } else { /* must be tnc mode */
+ a = next_addr(buf);
+#ifdef TNC_FILTER
+ if(NOT_ME(a)){
+ LOGL2("from_ip: (tnc) dumped - I am not destination!\n");
+ return;
+ }
+#endif
+ } /* end of tnc mode */
+ send_kiss(port, buf, l);
+}
+
+/*
+ * Send an ID frame out the KISS port.
+ */
+
+void
+do_beacon()
+{
+ int i;
+ unsigned char *p;
+
+ if(bclen == 0) return; /* nothing to do! */
+
+ if(bclen < 0) { /* build the id string */
+ p = bcbuf;
+ *p++ = ('I'<<1);
+ *p++ = ('D'<<1);
+ *p++ = (' '<<1);
+ *p++ = (' '<<1);
+ *p++ = (' '<<1);
+ *p++ = (' '<<1);
+ *p++ = '\0' | 0x60; /* SSID, set reserved bits */
+
+ for(i=0;i<6;i++)*p++=mycallsign[i];
+ *p++ = mycallsign[6] | 0x60; /* ensure reserved bits are set */
+ SETLAST(bcbuf+7); /* Set the E bit -- last address */
+
+ *p++ = 0x03; /* Control field -- UI frame */
+
+ *p++ = 0xf0; /* Protocol ID -- 0xf0 is no protocol */
+
+ strcpy(p, bc_text); /* add the text field */
+
+ bclen = 16 + strlen(bc_text); /* adjust the length nicely */
+ }
+
+ if(loglevel>2)dump_ax25frame("do_beacon: ", bcbuf, bclen);
+ stats.kiss_beacon_outs++;
+ send_kiss(0, bcbuf, bclen);
+}
+
+/*
+ * return true if the addresses supplied match
+ * modified for wildcarding by vk5xxx
+ */
+int
+addrmatch(a,b)
+unsigned char *a, *b;
+{
+ if((*a=='\0') || (*b=='\0'))return 0;
+
+ if((*a++^*b++)&0xfe)return 0; /* "K" */
+ if((*a++^*b++)&0xfe)return 0; /* "A" */
+ if((*a++^*b++)&0xfe)return 0; /* "9" */
+ if((*a++^*b++)&0xfe)return 0; /* "W" */
+ if((*a++^*b++)&0xfe)return 0; /* "S" */
+ if((*a++^*b++)&0xfe)return 0; /* "B" */
+ if(((*b++)&0x1e)==0)return 1; /* ssid 0 matches all ssid's */
+ if((*a++^*b)&0x1e)return 0; /* ssid */
+/* if((*a++^*b++)&0x1e)return 0; ssid (how it was ...) */
+ return 1;
+}
+
+/*
+ * return pointer to the next station to get this packet
+ */
+unsigned char *
+next_addr(f)
+unsigned char *f;
+{
+ unsigned char *a;
+
+/* If no digis, return the destination address */
+ if(NO_DIGIS(f))return f;
+
+/* check each digi field. The first one that hasn't seen it is the one */
+ a = f + 7;
+ do {
+ a += 7;
+ if(NOTREPEATED(a))return a;
+ }while(NOT_LAST(a));
+
+/* all the digis have seen it. return the destination address */
+ return f;
+}
+
+/*
+ * tack on the CRC for the frame. Note we assume the buffer is long
+ * enough to have the two bytes tacked on.
+ */
+void
+add_crc(buf, l)
+unsigned char *buf;
+int l;
+{
+ unsigned short int u;
+
+ u = compute_crc(buf, l);
+ buf[l] = u&0xff; /* lsb first */
+ buf[l+1] = (u>>8)&0xff; /* msb next */
+}
+
+/*
+ * Dump AX25 frame.
+ */
+void
+dump_ax25frame(t, buf, l)
+unsigned char *buf;
+char *t;
+int l;
+{
+#ifdef DEBUG
+ int i;
+#endif
+ unsigned char *a;
+
+ printf("%s AX25: (l=%3d) ", t, l);
+
+ if(l<15){
+ printf("Bogus size...\n");
+ return;
+ }
+
+ printf("%s -> ", call_to_a(buf+7));
+ printf("%s", call_to_a(buf));
+
+ if(ARE_DIGIS(buf)){
+ printf(" v");
+ a = buf+7;
+ do{
+ a+=7;
+ printf(" %s", call_to_a(a));
+ if(REPEATED(a))printf("*");
+ }while(NOT_LAST(a));
+ }
+
+ printf("\n");
+
+#ifdef DEBUG
+ for(i=0;i<l;i++)printf("%02x ",buf[i]);
+ printf("\n");
+#endif
+
+ fflush(stdout);
+}
diff --git a/ax25ipd/routing.c b/ax25ipd/routing.c
new file mode 100644
index 0000000..3f771b3
--- /dev/null
+++ b/ax25ipd/routing.c
@@ -0,0 +1,264 @@
+/* routing.c Routing table manipulation routines
+ *
+ * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
+ * This software may be freely used, distributed, or modified, providing
+ * this header is not removed.
+ *
+ */
+
+#include <stdio.h>
+#include "ax25ipd.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <memory.h>
+
+/* The routing table structure is not visible outside this module. */
+
+struct route_table_entry {
+ unsigned char callsign[7]; /* the callsign and ssid */
+ unsigned char padcall; /* always set to zero */
+ unsigned char ip_addr[4]; /* the IP address */
+ unsigned short udp_port; /* the port number if udp */
+ unsigned char pad1;
+ unsigned char pad2;
+ unsigned int flags; /* route flags */
+ struct route_table_entry* next;
+};
+
+struct route_table_entry* route_tbl;
+struct route_table_entry* default_route;
+
+/* The Broadcast address structure is not visible outside this module either */
+
+struct bcast_table_entry {
+ unsigned char callsign[7]; /* The broadcast address */
+ struct bcast_table_entry* next;
+};
+
+struct bcast_table_entry* bcast_tbl;
+
+/* Initialize the routing module */
+void
+route_init()
+{
+ route_tbl = NULL;
+ default_route = NULL;
+ bcast_tbl = NULL;
+}
+
+/* Add a new route entry */
+void
+route_add(ip, call, udpport, flags)
+unsigned char *ip;
+unsigned char *call;
+int udpport;
+unsigned int flags;
+{
+ struct route_table_entry *rl, *rn;
+ int i;
+
+ /* Check we have an IP address */
+ if (ip==NULL)
+ return;
+
+ /* Check we have a callsign */
+ if (call==NULL)
+ return;
+
+ /* Find the last entry in the list */
+ rl=route_tbl;
+ if (route_tbl)
+ while (rl->next)
+ rl=rl->next;
+
+ rn=(struct route_table_entry*)malloc(sizeof(struct route_table_entry));
+
+ /* Build this entry ... */
+ for (i=0; i<6; i++)
+ rn->callsign[i] = call[i] & 0xfe;
+ rn->callsign[6] = (call[6] & 0x1e) | 0x60;
+ rn->padcall = 0;
+ memcpy(rn->ip_addr, ip, 4);
+ rn->udp_port = htons(udpport);
+ rn->pad1 = 0;
+ rn->pad2 = 0;
+ rn->flags = flags;
+ rn->next=NULL;
+
+ /* Update the default_route pointer if this is a default route */
+ if (flags & AXRT_DEFAULT)
+ default_route=rn;
+
+ if (rl) /* ... the list is already started add the new route */
+ rl->next=rn;
+ else /* ... start the list off */
+ route_tbl=rn;
+
+ /* Log this entry ... */
+ LOGL4("added route: %s\t%s\t%s\t%d\t%d\n",
+ call_to_a(rn->callsign),
+ (char *)inet_ntoa(*(struct in_addr *)rn->ip_addr),
+ rn->udp_port ? "udp" : "ip",
+ ntohs(rn->udp_port), flags);
+
+ return;
+}
+
+/* Add a new broadcast address entry */
+void
+bcast_add(call)
+unsigned char* call;
+{
+ struct bcast_table_entry *bl, *bn;
+ int i;
+
+ /* Check we have a callsign */
+ if (call==NULL)
+ return;
+
+ /* Find the last entry in the list */
+ bl=bcast_tbl;
+ if (bcast_tbl)
+ while (bl->next)
+ bl=bl->next;
+
+ bn=(struct bcast_table_entry*)malloc(sizeof(struct bcast_table_entry));
+
+ /* Build this entry ... */
+ for (i=0; i<6; i++)
+ bn->callsign[i] = call[i] & 0xfe;
+ bn->callsign[6] = (call[6] & 0x1e) | 0x60;
+
+ bn->next=NULL;
+
+ if (bl) /* ... the list is already started add the new route */
+ bl->next=bn;
+ else /* ... start the list off */
+ bcast_tbl=bn;
+
+ /* Log this entry ... */
+ LOGL4("added broadcast address: %s\n", call_to_a(bn->callsign));
+}
+
+/*
+ * Return an IP address and port number given a callsign.
+ * We return a pointer to the address; the port number can be found
+ * immediately following the IP address. (UGLY coding; to be fixed later!)
+ */
+
+unsigned char *
+call_to_ip(call)
+unsigned char *call;
+{
+ struct route_table_entry* rp;
+ unsigned char mycall[7];
+ int i;
+
+ if(call==NULL)
+ return NULL;
+
+ for(i=0; i<6; i++)
+ mycall[i] = call[i] & 0xfe;
+
+ mycall[6] = (call[6] & 0x1e) | 0x60;
+
+ LOGL4("lookup call %s ",call_to_a(mycall));
+
+ rp=route_tbl;
+ while (rp) {
+ if (addrmatch(mycall,rp->callsign)) {
+ LOGL4("found ip addr %s\n",
+ (char *)inet_ntoa(*(struct in_addr *)rp->ip_addr));
+ return rp->ip_addr;
+ }
+ rp=rp->next;
+ }
+
+ /*
+ * No match found in the routing table, use the default route if
+ * we have one defined.
+ */
+ if (default_route) {
+ LOGL4("failed, using default ip addr %s\n",
+ (char *)inet_ntoa(*(struct in_addr *)default_route->ip_addr));
+ return default_route->ip_addr;
+ }
+
+ LOGL4("failed.\n");
+ return NULL;
+}
+
+/*
+ * Accept a callsign and return true if it is a broadcast address, or false
+ * if it is not found on the list
+ */
+int
+is_call_bcast(call)
+unsigned char *call;
+{
+ struct bcast_table_entry* bp;
+ unsigned char bccall[7];
+ int i;
+
+ if(call==NULL)
+ return(FALSE);
+
+ for(i=0; i<6; i++)
+ bccall[i] = call[i] & 0xfe;
+
+ bccall[6] = (call[6] & 0x1e) | 0x60;
+
+ LOGL4("lookup broadcast %s ",call_to_a(bccall));
+
+ bp=bcast_tbl;
+ while (bp) {
+ if (addrmatch(bccall,bp->callsign)) {
+ LOGL4("found broadcast %s\n", call_to_a(bp->callsign));
+ return(TRUE);
+ }
+ bp=bp->next;
+ }
+ return(FALSE);
+}
+
+/* Traverse the routing table, transmitting the packet to each bcast route */
+void
+send_broadcast(buf, l)
+unsigned char *buf;
+int l;
+{
+ struct route_table_entry *rp;
+
+ rp=route_tbl;
+ while (rp) {
+ if (rp->flags & AXRT_BCAST) {
+ send_ip(buf, l, rp->ip_addr);
+ }
+ rp=rp->next;
+ }
+}
+
+/* print out the list of routes */
+void
+dump_routes()
+{
+ struct route_table_entry* rp;
+ int i;
+
+ for (rp=route_tbl, i=0; rp; rp=rp->next)
+ i++;
+
+ LOGL1("\n%d active routes.\n",i);
+
+ rp=route_tbl;
+ while (rp) {
+ LOGL1(" %s\t%s\t%s\t%d\t%d\n",
+ call_to_a(rp->callsign),
+ (char *)inet_ntoa(*(struct in_addr *)rp->ip_addr),
+ rp->udp_port ? "udp" : "ip",
+ ntohs(rp->udp_port), rp->flags);
+ rp=rp->next;
+ }
+ fflush(stdout);
+}
+