From 0fceb64d25ff3d9586549bb43d971c5eef904330 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 7 Jun 1999 10:23:42 +0200 Subject: Import ax25-apps 0.0.1 from tarball --- ax25ipd/Makefile.am | 19 ++ ax25ipd/Makefile.in | 404 ++++++++++++++++++++++++++++++++++ ax25ipd/ax25ipd.8 | 64 ++++++ ax25ipd/ax25ipd.c | 163 ++++++++++++++ ax25ipd/ax25ipd.conf.5 | 159 ++++++++++++++ ax25ipd/ax25ipd.h | 182 ++++++++++++++++ ax25ipd/config.c | 404 ++++++++++++++++++++++++++++++++++ ax25ipd/crc.c | 171 +++++++++++++++ ax25ipd/io.c | 574 +++++++++++++++++++++++++++++++++++++++++++++++++ ax25ipd/kiss.c | 201 +++++++++++++++++ ax25ipd/process.c | 338 +++++++++++++++++++++++++++++ ax25ipd/routing.c | 264 +++++++++++++++++++++++ 12 files changed, 2943 insertions(+) create mode 100644 ax25ipd/Makefile.am create mode 100644 ax25ipd/Makefile.in create mode 100644 ax25ipd/ax25ipd.8 create mode 100644 ax25ipd/ax25ipd.c create mode 100644 ax25ipd/ax25ipd.conf.5 create mode 100644 ax25ipd/ax25ipd.h create mode 100644 ax25ipd/config.c create mode 100644 ax25ipd/crc.c create mode 100644 ax25ipd/io.c create mode 100644 ax25ipd/kiss.c create mode 100644 ax25ipd/process.c create mode 100644 ax25ipd/routing.c (limited to 'ax25ipd') 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 +.br +Michael Durrant <> +.br +D. Jeff Dionne VE3DJF +.br +Rob Mayfield VK5XXX/VK5ZEU +.br +Terry Dawson VK2KTJ +.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 +#include +#include + +#include +#include + +#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 []\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 [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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#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;i15)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>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 +#include +#include +#include +#include +#include +#ifdef USE_ICMP +#include +#endif +#include +#include +#include +#include +#include +#include + +#ifdef __bsdi__ +#define USE_TERMIOS +#endif + +#ifndef USE_TERMIOS +#ifndef USE_TERMIO +#define USE_SGTTY +#endif +#endif + +#ifdef USE_TERMIOS +#include +struct termios nterm; +#endif + +#ifdef USE_TERMIO +#include +struct termio nterm; +#endif + +#ifdef USE_SGTTY +#include +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)&&(n0){ + if(n!=nc){ + LOGL4("%d ",n); /* no-one said loglevel 4 */ + } else { + LOGL4("%d\n",n); /* was efficient!!! */ + } + } + } while( ((n>0)&&(n= 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 +#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;i0){ + /* 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= 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 +/* 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 +#include "ax25ipd.h" +#include +#include +#include + +/* 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); +} + -- cgit v1.2.3