summaryrefslogtreecommitdiffstats
path: root/ax25rtd
diff options
context:
space:
mode:
Diffstat (limited to 'ax25rtd')
-rw-r--r--ax25rtd/Makefile.am25
-rw-r--r--ax25rtd/Makefile.in342
-rw-r--r--ax25rtd/README268
-rw-r--r--ax25rtd/TODO10
-rw-r--r--ax25rtd/ax25rtctl.c437
-rw-r--r--ax25rtd/ax25rtd.c233
-rw-r--r--ax25rtd/ax25rtd.conf82
-rw-r--r--ax25rtd/ax25rtd.h163
-rw-r--r--ax25rtd/cache_ctl.c330
-rw-r--r--ax25rtd/cache_dump.c141
-rw-r--r--ax25rtd/config.c736
-rw-r--r--ax25rtd/listener.c579
12 files changed, 3346 insertions, 0 deletions
diff --git a/ax25rtd/Makefile.am b/ax25rtd/Makefile.am
new file mode 100644
index 0000000..b804faa
--- /dev/null
+++ b/ax25rtd/Makefile.am
@@ -0,0 +1,25 @@
+
+etcfiles = ax25rtd.conf
+etcdir = $(sysconfdir)/ax25
+
+installconf:
+ $(mkinstalldirs) $(DESTDIR)$(etcdir)
+ @list='$(etcfiles)'; for p in $$list; do \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \
+ done
+
+sbin_PROGRAMS = ax25rtd ax25rtctl
+
+LDADD = $(AX25_LIB)
+
+EXTRA_DIST = $(etcfiles)
+
+ax25rtd_SOURCES = \
+ ax25rtd.c \
+ ax25rtd.h \
+ cache_ctl.c \
+ cache_dump.c \
+ config.c \
+ listener.c
+
diff --git a/ax25rtd/Makefile.in b/ax25rtd/Makefile.in
new file mode 100644
index 0000000..8925278
--- /dev/null
+++ b/ax25rtd/Makefile.in
@@ -0,0 +1,342 @@
+# 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@
+
+etcfiles = ax25rtd.conf
+etcdir = $(sysconfdir)/ax25
+
+sbin_PROGRAMS = ax25rtd ax25rtctl
+
+LDADD = $(AX25_LIB)
+
+EXTRA_DIST = $(etcfiles)
+
+ax25rtd_SOURCES = ax25rtd.c ax25rtd.h cache_ctl.c cache_dump.c config.c listener.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@
+ax25rtd_OBJECTS = ax25rtd.o cache_ctl.o cache_dump.o config.o \
+listener.o
+ax25rtd_LDADD = $(LDADD)
+ax25rtd_DEPENDENCIES =
+ax25rtd_LDFLAGS =
+ax25rtctl_SOURCES = ax25rtctl.c
+ax25rtctl_OBJECTS = ax25rtctl.o
+ax25rtctl_LDADD = $(LDADD)
+ax25rtctl_DEPENDENCIES =
+ax25rtctl_LDFLAGS =
+CFLAGS = @CFLAGS@
+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 $@
+DIST_COMMON = README Makefile.am Makefile.in TODO
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(ax25rtd_SOURCES) ax25rtctl.c
+OBJECTS = $(ax25rtd_OBJECTS) ax25rtctl.o
+
+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 ax25rtd/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:
+
+ax25rtd: $(ax25rtd_OBJECTS) $(ax25rtd_DEPENDENCIES)
+ @rm -f ax25rtd
+ $(LINK) $(ax25rtd_LDFLAGS) $(ax25rtd_OBJECTS) $(ax25rtd_LDADD) $(LIBS)
+
+ax25rtctl: $(ax25rtctl_OBJECTS) $(ax25rtctl_DEPENDENCIES)
+ @rm -f ax25rtctl
+ $(LINK) $(ax25rtctl_LDFLAGS) $(ax25rtctl_OBJECTS) $(ax25rtctl_LDADD) $(LIBS)
+
+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 = ax25rtd
+
+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
+ax25rtctl.o: ax25rtctl.c ../config.h ../pathnames.h
+ax25rtd.o: ax25rtd.c ../pathnames.h ax25rtd.h
+cache_ctl.o: cache_ctl.c ax25rtd.h
+cache_dump.o: cache_dump.c ax25rtd.h
+config.o: config.c ../pathnames.h ax25rtd.h
+listener.o: listener.c ../pathnames.h ax25rtd.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-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: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+
+
+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 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
+
+
+installconf:
+ $(mkinstalldirs) $(DESTDIR)$(etcdir)
+ @list='$(etcfiles)'; for p in $$list; do \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(etcdir)/$$p; \
+ done
+
+# 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/ax25rtd/README b/ax25rtd/README
new file mode 100644
index 0000000..a7bf2c4
--- /dev/null
+++ b/ax25rtd/README
@@ -0,0 +1,268 @@
+*****************************************************************
+* Please send all comments and suggestions regarding ax25rtd to *
+* Klaus Kudielka (oe1kib@oe1xtu.ampr.org). *
+*****************************************************************
+
+Just a quick small README...
+This will hopefully go into the man pages ASAP.
+
+Ax25routed
+----------
+
+/usr/sbin/ax25rtd
+
+This is a daemon that:
+
+- emulates the ceased "autorouter" of Linux Kernel AX.25
+- sets up ARP entries automagically
+- may adjust IP routes and encapsulation mode
+ (although I really do not recomment to use this feature...)
+
+The "autorouter" is not really an autorouter. It just listens to the AX.25
+traffic on your ports and uses this information to setup AX.25 routes. This
+can be turned on or off by altering the configuration file
+/etc/ax25/ax25rtd.conf.
+
+Ax25routed provides a socket /var/ax25/ax25rtd/control which is used for
+runtime maintainance through ax25rtctl or to set up new routes by other
+daemons (a Flexnet router, perhaps?)
+
+On startup ax25rtd reads the configuration file and afterwards preloads
+the caches from the files /var/ax25/ax25rtd/ax25_routes and
+/var/ax25/ax25rtd/ip_routes. On SIGTERM or ax25rtctl --save it saves the
+caches to those files.
+
+ax25rtd.conf
+---------------
+
+The file /etc/ax25/ax25rtd.conf is the configuration file for ax25rtd.
+The parameters of the options shown here are the default values except the
+ones marked with (example)
+
+ax25-maxroutes 256
+ip-maxroutes 256
+
+ The maximum size of the three lists / caches. On overflow,
+ ax25rtd will substitute the oldest entry with the new one.
+[1k2]
+ This marks the beginning of per-port definitions. Note that
+ you have to use port names as defined in axports(5) here,
+ anywhere else you may use the port or the device name.
+
+ax25-learn-routes no
+
+ Set this to "yes", ax25rtd will add the routing information
+ for every heard frame (with complete digipeater path) to the
+ kernel AX.25 routing table. Note that ax25rtd's internal cache
+ will be updated anyway, regardless of this option.
+
+ax25-learn-only-mine no
+
+ If you set it to "yes", only frames that are sent to (1) the
+ interface callsign, (2) any of the listeners on this device, or
+ (3) the callsigns specified by ax25-more-mycalls will be used
+ to update the internal cache and (depending on
+ ax25-learn-routes) the kernel routing table.
+
+ax25-add-path db0ach (example)
+
+ This is useful on DAMA digipeaters. In this case, the DAMA
+ master has to be used for _every_ AX.25 connection, thus
+ ax25rtd will add this digipeater(s) to every target we learn
+ that has no digipeater path (yet). "db0ach" is just an
+ example here.
+
+ax25-more-mycalls dl1bke dl1bke-8 (example)
+
+ You can specify more calls as calls here that belong to
+ this interface... "dl1bke" and "dl1bke-8" are examples.
+
+ip-learn-routes no
+
+ If set to "yes", ax25rtd will modify the IP routing table if it
+ receives an IP frame (directed to us). This is dangerous!
+
+ It should not screw up your routing table, though. Ax25rtd
+ recognizes the netmask of the device and will adjust the route
+ only if it fits the netmask and the old route points to
+ one of the devices ax25rtd knows about (hence an AX.25 device).
+
+ The problems begin if you have more than one port and a user
+ is able to hear your outgoing traffic on at least two of them.
+ Due to technical reasons ax25rtd adjusts the route _after_ the
+ kernel has sent the reply to the received TCP frame already.
+ This has technical reasons.
+
+ If the remote does the same both are switching between the two
+ ports.
+
+ Don't use this feature unless you know what you are doing.
+
+ It _should_ be safe do enable this on one-port machines, although
+ I strongly recommend to set a network route instead, i.e.:
+
+ route add -net 44.0.0.0 scc3
+
+ Note that ax25rtd's internal cache will be updated anyway,
+ regardless of this option.
+
+irtt <irtt>
+
+ If ip-learn-routes is enabled this will assign newly added
+ routes an initial round trip time (IRTT) for TCP. <irtt>
+ is measured in msec, hence
+
+ irtt 10000
+
+ sets the irtt to 10 seconds. A value of 0 disables this
+ feature (default).
+
+ip-adjust-mode no
+
+ If you set this option to "yes" ax25rtd will change the IP
+ encapsulation mode according to the last received IP frame.
+
+ The problem with this option is that the kernel AX.25 sends
+ a received IP frame to the IP layer regardless if it was
+ sent in UI frame encapsulation "mode datagram (dg)" or
+ in I frame encaps, hence in an AX.25 connection, "mode virtual
+ connect (vc)". The Linux kernel will respond to this frame
+ before ax25rtd can adjust the mode. If the remote does the
+ same... You get the picture.
+
+ Don't use this feature unless you know what you are doing.
+
+arp-add no
+
+ This option, if set to "yes", changes the ARP table to the
+ source callsign of the received frame. It should be harmless,
+ just has the the effect that if it is a new entry, the Linux
+ ARP code will send one ARP request before ax25rtd has adjust
+ the ARP table. If there was already an existing ARP entry
+ for this IP route, one IP datagram will be sent to the old
+ address. Not really a problem, I hope.
+
+
+Ax25rtctl
+---------
+
+/usr/sbin/ax25rtctl <option>
+
+This is a program to control ax25rtd. There are several options:
+
+ax25rtctl --add ax25 <callsign> <dev> <time> [digipeater]
+ax25rtctl -a ax25 <callsign> <dev> <time> [digipeater]
+
+ Add an entry to the AX.25 routing table. If time is "0"
+ this entry will be marked permanent, hence: the daemon will not
+ overwrite this route.
+
+ax25rtctl --del ax25 <callsign> <dev>
+ax25rtctl -d ax25 <callsign> <dev>
+
+ Remove an entry from the AX.25 routing table.
+
+ax25rtctl --add ip <ip> <dev> <time> <call> <ipmode>
+ax25rtctl -a ip <ip> <dev> <time> <call> <ipmode>
+
+ Add an entry to the IP routing table. If time is "0" the
+ entry will be marked permanent.
+
+ax25rtctl --del ip <ip>
+ax25rtctl -d ip <ip>
+
+ Remove an entry from the IP routing table.
+
+ax25rtctl --list ax25
+ax25rtctl -l ax25
+
+ Lists the content of the cache for the AX.25 routing table.
+
+ax25rtctl --list ip
+ax25rtctl -l ip
+
+ Lists the content of the cache for the IP routing table.
+
+ax25rtctl --expire <minutes>
+ax25rtctl -e <minutes>
+
+ Removes the entries older than <minutes> from the caches and
+ the kernel routing tables.
+
+ax25rtctl --save
+ax25rtctl -s
+
+ Saves the AX.25 and IP cache to /var/ax25/ax25rtd/ax25_routes and
+ /var/ax25/ax25rtd/ip_routes (or the files specified in
+ /etc/ax25/ax25rtd.conf).
+
+ax25rtctl --reload
+ax25rtctl -r
+
+ Reloads the config file /etc/ax25/ax25rtd.conf. This will
+ *not* affect the caches or the heard list.
+
+ax25rtctl --shutdown
+ax25rtctl -q
+
+ Same as 'killall -TERM ax25rtd' ;-)
+
+
+ax25rtctl --version
+ax25rtctl -V
+
+ Guess what...
+
+
+Note that you can specify either the port name (as defined in
+/etc/ax25/axports) or the interface name (shown by ifconfig). If names
+conflict (i.e. port scc0 is in fact interface scc3, and vica versa), the
+interface name has precedence over the port name. Example:
+
+ ax25rtctl --add ax25 dl0tha scc3 0 db0pra
+
+is equivalent to
+
+ ax25rtctl --add ax25 dl0tha 9k6 0 dbpra
+
+All commands return port names in their output, though.
+With one exception: ax25_routes and ip_routes use interface names.
+
+
+/var/ax25/ax25rtd/control
+----------------------------
+
+The commands recognized on this socket are:
+
+add ax25 <callsign> <dev> <time> [<digipeater>]
+ Add an AX.25 route
+add ip <ip> <dev> <time> <call> <mode>
+ Add an IP route & mode
+
+del ax25 <callsign> <dev>
+ Remove an AX.25 route from cache an kernel routing table
+del ip <ip>
+ Remove an IP route from cache and kernel routing table
+
+list [ax25|ip]
+ List cache entries.
+
+reload
+ Reload config
+
+save
+ Save cache
+
+expire <min>
+ Expire cache entries older than <min> minutes
+
+shutdown
+ Save caches and exit
+
+version
+ Prints the version of the ax25rtd
+
+
+Note that every command has to end with a '\n', and every line of the
+response ends with an '\n' as well. The last line of a cache list
+is just a period alone on a line (".\n").
diff --git a/ax25rtd/TODO b/ax25rtd/TODO
new file mode 100644
index 0000000..19e6627
--- /dev/null
+++ b/ax25rtd/TODO
@@ -0,0 +1,10 @@
+
+What to do next?
+
+- convert the content of README to manual pages
+- Use partly digipeated frames for the AX.25 routing table if we are the
+ next digipeater
+- A solution for IP encapsulation mode changes
+- Support for Flexnet routing information
+- Support PE1CHL's autorouter (Rob, you promised to send me the specs...)
+- A similar program for NET/ROM
diff --git a/ax25rtd/ax25rtctl.c b/ax25rtd/ax25rtctl.c
new file mode 100644
index 0000000..6f40423
--- /dev/null
+++ b/ax25rtd/ax25rtctl.c
@@ -0,0 +1,437 @@
+/* $Id: ax25rtctl.c,v 1.7 1997/06/05 18:52:55 oe1kib Exp oe1kib $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <config.h>
+#include "../pathnames.h"
+
+static const struct option lopts[] = {
+ {"add", 1, 0, 'a'},
+ {"del", 1, 0, 'd'},
+ {"list", 1, 0, 'l'},
+ {"expire", 1, 0, 'e'},
+ {"save", 0, 0, 's'},
+ {"reload", 0, 0, 'r'},
+ {"shutdown", 0, 0, 'q'},
+ {"Version", 0, 0, 'V'},
+ {"help", 0, 0, 'h'},
+ {"debug", 0, 0, 'x'},
+ {"version", 0, 0, 'v'},
+ {NULL, 0, 0, 0 }
+};
+
+static const char *sopts = "a:d:l:e:srqvVh";
+
+static void usage(void)
+{
+ fprintf(stderr,"usage:\n");
+ fprintf(stderr,"ax25rtctl -a|--add ax25 <callsign> <dev> <time> [digipeater]\n");
+ fprintf(stderr," -a|--add ip <ip> <dev> <time> <call> <ipmode>\n");
+ fprintf(stderr," -d|--del ax25 <callsign> <dev>\n");
+ fprintf(stderr," -d|--del ip <ip>\n");
+ fprintf(stderr," -l|--list ax25|ip\n");
+ fprintf(stderr," -e|--expire <minutes>\n");
+ fprintf(stderr," -s|--save\n");
+ fprintf(stderr," -r|--reload\n");
+ fprintf(stderr," -q|--shutdown\n");
+ fprintf(stderr," -V|--Version\n");
+ fprintf(stderr," -h|--help\n");
+ fprintf(stderr," -v|--version\n");
+ exit(1);
+}
+
+static int open_socket(void)
+{
+ int sock, addrlen;
+ struct sockaddr_un addr;
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror("ax25rtctl socket");
+ exit(1);
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, DATA_AX25ROUTED_CTL_SOCK);
+ addrlen = strlen(DATA_AX25ROUTED_CTL_SOCK) + sizeof(addr.sun_family);
+
+ if (connect(sock, (struct sockaddr *) &addr, addrlen) < 0)
+ {
+ perror("ax25rtctl connect");
+ exit(1);
+ }
+
+ return sock;
+}
+
+static int wsock(int sock, char *s)
+{
+ return write(sock, s, strlen(s));
+}
+
+static char *get_next_arg(char **p)
+{
+ char *p2;
+
+ if (p == NULL || *p == NULL)
+ return NULL;
+
+ p2 = *p;
+ for (; *p2 && *p2 == ' '; p2++) ;
+ if (!*p2)
+ return NULL;
+
+ *p = strchr(p2, ' ');
+ if (*p != NULL)
+ {
+ **p = '\0';
+ (*p)++;
+ }
+
+ return p2;
+}
+
+static void list_ax25(void)
+{
+ int sock, len, offs;
+ char buf[512], *b, *s, *digi, *call, *dev, *ct;
+ time_t t;
+
+ sock = open_socket();
+
+ wsock(sock, "list ax25\n");
+
+ offs = 0;
+
+ printf("Callsign Port Last update Path\n");
+
+/*
+ DB0PRA-15 scc3 Tue Aug 6 16:35:38 1996
+*/
+
+ while(1)
+ {
+ len = read(sock, buf+offs, sizeof(buf)-offs-1);
+ if (len <= 0)
+ {
+ close(sock);
+ return;
+ }
+
+ buf[len+offs] = '\0';
+ s = buf;
+ for (s = buf; (b = strchr(s, '\n')) != NULL; s = b+1)
+ {
+ *b = '\0';
+
+ if (s[0] == '.')
+ {
+ close(sock);
+ return;
+ }
+
+ call = get_next_arg(&s);
+ dev = get_next_arg(&s);
+ t = strtol(get_next_arg(&s), NULL, 16);
+
+ if (t == 0)
+ {
+ ct = "(permanent)";
+ ct = strdup(ct);
+ } else {
+ ct = strdup(ctime(&t));
+ ct[strlen(ct)-6] = '\0';
+ }
+
+ printf("%-9s %-6s %s", call, dev, ct);
+
+ free(ct);
+
+ while ( (digi = get_next_arg(&s)) != NULL)
+ printf(" %s", digi);
+
+ printf("\n");
+ }
+
+ if (b == NULL && s != NULL)
+ {
+ offs = strlen(s);
+ if (offs)
+ memcpy(buf, s, offs);
+ }
+ }
+
+ close(sock);
+}
+
+static void list_ip(void)
+{
+ int sock, len, offs;
+ char buf[512], *b, *s, *ip, *call, *dev, *ct, *mode;
+ time_t t;
+
+ sock = open_socket();
+
+ wsock(sock, "list ip\n");
+
+ offs = 0;
+ printf("IP Address Port Callsign Mode Last update\n");
+
+/*
+ 255.255.255.255 scc3 DB0PRA-15 v Thu Jan 7 06:54:19 1971
+ */
+ while(1)
+ {
+ len = read(sock, buf+offs, sizeof(buf)-offs-1);
+ if (len <= 0)
+ {
+ close(sock);
+ return;
+ }
+
+ buf[len+offs] = '\0';
+ s = buf;
+ for (s = buf; (b = strchr(s, '\n')) != NULL; s = b+1)
+ {
+ *b = '\0';
+
+ if (s[0] == '.')
+ {
+ close(sock);
+ return;
+ }
+
+ ip = get_next_arg(&s);
+ dev = get_next_arg(&s);
+ t = strtol(get_next_arg(&s), NULL, 16);
+ call = get_next_arg(&s);
+ mode = get_next_arg(&s);
+
+ if (t == 0)
+ {
+ ct = "(permanent)";
+ } else {
+ ct = ctime(&t);
+ ct[strlen(ct)-6] = '\0';
+ }
+
+ printf("%-15s %-6s %-9s %-4s %s\n", ip, dev, call, mode, ct);
+ }
+
+ if (b == NULL && s != NULL)
+ {
+ offs = strlen(s);
+ if (offs)
+ memcpy(buf, s, offs);
+ }
+ }
+
+ close(sock);
+}
+
+static void Version(void)
+{
+ int sock;
+ char buf[256];
+
+ printf("ax25rtctl $Revision: 1.7 $\n");
+ sock = open_socket();
+ wsock(sock, "version\n");
+ read(sock, buf, sizeof(buf));
+ printf("%s", buf);
+ close(sock);
+}
+
+static void debug(void)
+{
+ int sock, n, k;
+ unsigned char buf[256];
+ fd_set fd_set, fd_set2;
+ struct timeval tv;
+
+
+ sock = open_socket();
+
+ while (1)
+ {
+ FD_ZERO(&fd_set);
+ FD_SET(0, &fd_set);
+ FD_SET(sock, &fd_set);
+
+ FD_ZERO(&fd_set2);
+ FD_SET(sock, &fd_set2);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if (select(sock+1, &fd_set, NULL, &fd_set2, &tv) < 0)
+ {
+ perror("socket gone");
+ exit(1);
+ }
+
+ if (FD_ISSET(sock, &fd_set2))
+ exit(0);
+
+ if (FD_ISSET(0, &fd_set))
+ {
+ n = read(0, buf, sizeof(buf));
+ if (n)
+ {
+ k = write(sock, buf, n);
+ if (k <= 0)
+ exit(0);
+ }
+ }
+
+ if (FD_ISSET(sock, &fd_set))
+ {
+ n = read(sock, buf, sizeof(buf));
+ if (n)
+ write(0, buf, n);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int sock, cmd, k, len;
+ unsigned char buf[256];
+ int opt_ind = 0;
+ long when;
+
+ cmd = getopt_long(argc, argv, sopts, lopts, &opt_ind);
+ switch (cmd)
+ {
+ case 'a':
+ if (!strcmp(optarg, "ax25"))
+ {
+ if (argc < optind+3)
+ usage();
+
+ len = sprintf(buf, "add ax25");
+ for (k = optind; k < argc; k++)
+ len += sprintf(buf+len, " %s", argv[k]);
+ sprintf(buf+len, "\n");
+
+ sock = open_socket();
+ wsock(sock, buf);
+ close(sock);
+ } else
+ if (!strcmp(optarg, "ip"))
+ {
+ if (argc < optind+5)
+ usage();
+
+ len = sprintf(buf, "add ip");
+ for (k = optind; k < argc; k++)
+ len += sprintf(buf+len, " %s", argv[k]);
+ sprintf(buf+len, "\n");
+
+ sock = open_socket();
+ wsock(sock, buf);
+ close(sock);
+ } else
+ usage();
+ return 0;
+ case 'd':
+ if (!strcmp(optarg, "ax25"))
+ {
+ if (argc < optind+2)
+ usage();
+
+ sprintf(buf, "del ax25 %s %s\n", argv[optind], argv[optind+1]);
+
+ sock = open_socket();
+ wsock(sock, buf);
+ close(sock);
+ } else
+ if (!strcmp(optarg, "ip"))
+ {
+ if (argc < optind+1)
+ usage();
+
+ sprintf(buf, "del ip %s\n", argv[optind]);
+
+ sock = open_socket();
+ wsock(sock, buf);
+ close(sock);
+ } else
+ usage();
+ return 0;
+ case 'l':
+ if (!strcmp(optarg, "ax25"))
+ list_ax25();
+ else if (!strcmp(optarg, "ip"))
+ list_ip();
+ else
+ usage();
+ return 0;
+ case 'e':
+ when = atoi(optarg);
+ if (when <= 0)
+ usage();
+ sock = open_socket();
+ sprintf(buf, "expire %ld\n", when);
+ wsock(sock, buf);
+ close(sock);
+ return 0;
+ case 's':
+ sock = open_socket();
+ wsock(sock, "save\n");
+ close(sock);
+ return 0;
+ case 'r':
+ sock = open_socket();
+ wsock(sock, "reload\n");
+ close(sock);
+ return 0;
+ case 'q':
+ sock = open_socket();
+ wsock(sock, "shutdown\n");
+ close(sock);
+ return 0;
+ case 'V':
+ Version();
+ return 0;
+ case 'v':
+ printf("ax25rtctl: %s\n", VERSION);
+ return 0;
+ case 'x':
+ debug();
+ case ':':
+ case 'h':
+ case '?':
+ default:
+ usage();
+ }
+ usage();
+ return 1;
+}
diff --git a/ax25rtd/ax25rtd.c b/ax25rtd/ax25rtd.c
new file mode 100644
index 0000000..0fdbb39
--- /dev/null
+++ b/ax25rtd/ax25rtd.c
@@ -0,0 +1,233 @@
+/* $Id: ax25rtd.c,v 1.6 1996/10/23 18:27:43 jreuter Exp jreuter $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * This daemon tries to learn AX.25, ARP, IP route entries by listening
+ * to the AX.25 traffic. It caches up to 256 entries (in "FIFO" mode)
+ * and saves the cache on demand or at shutdown in /var/ax25/ax25rtd/ip_routes
+ * and /var/ax25/ax25rtd/ax25_routes. The configuration file is
+ * /etc/ax25/ax25rtd.conf, you can almost everything configure
+ * there. See ax25rtcl.c for runtime maintainance.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <netax25/ax25.h>
+#include <netax25/axconfig.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+
+#include "../pathnames.h"
+#include "ax25rtd.h"
+
+const char *Version = "ax25rtd $Revision: 1.6 $";
+config *Config = NULL;
+
+int reload = 0;
+
+ip_rt_entry * ip_routes = NULL;
+int ip_routes_cnt = 0;
+int ip_maxroutes = IP_MAXROUTES;
+
+ax25_rt_entry * ax25_routes = NULL;
+int ax25_routes_cnt = 0;
+int ax25_maxroutes = AX25_MAXROUTES;
+
+
+config *dev_get_config(char *dev)
+{
+ config *config;
+
+ for (config = Config; config; config = config->next)
+ if (!strcmp(config->dev, dev))
+ return config;
+
+ return port_get_config(dev);
+}
+
+config *port_get_config(char *port)
+{
+ config *config;
+
+ for (config = Config; config; config = config->next)
+ if (!strcmp(config->port, port))
+ return config;
+ return NULL;
+}
+
+void sig_reload(int d)
+{
+ reload = 1;
+ signal(SIGHUP, sig_reload);
+}
+
+void sig_debug(int d)
+{
+ fprintf(stderr, "config:\n");
+ dump_config(2);
+ fprintf(stderr, "ip-routes:\n");
+ dump_ip_routes(2, 0);
+ fprintf(stderr, "ax25-routes:\n");
+ dump_ax25_routes(2, 0);
+ signal(SIGUSR1, sig_debug);
+}
+
+void sig_term(int d)
+{
+ save_cache();
+ daemon_shutdown(0);
+}
+
+void daemon_shutdown(int reason)
+{
+ unlink(DATA_AX25ROUTED_CTL_SOCK);
+ exit(reason);
+}
+
+#define FD_MAX(fd) {fd_max = (fd > fd_max? fd : fd_max); FD_SET(fd, &fd_set);}
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[256];
+ int size, s;
+ int cntrl_s, cntrl_fd, cntrl_len;
+ struct sockaddr_un cntrl_addr;
+ fd_set fd_set, fd_set2;
+ int fd_max;
+
+ if (ax25_config_load_ports() == 0) {
+ fprintf(stderr, "ax25rtd: no AX.25 port configured\n");
+ return 1;
+ }
+
+ load_config();
+ load_cache();
+
+ if (fork())
+ return 0;
+
+ if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1)
+ {
+ perror("AX.25 socket");
+ return 1;
+ }
+
+ if ((cntrl_s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ perror("Control socket");
+ return 1;
+ }
+
+ unlink(DATA_AX25ROUTED_CTL_SOCK);
+
+ cntrl_addr.sun_family = AF_UNIX;
+ strcpy(cntrl_addr.sun_path, DATA_AX25ROUTED_CTL_SOCK);
+ cntrl_len = sizeof(cntrl_addr.sun_family) + strlen(DATA_AX25ROUTED_CTL_SOCK);
+
+ if (bind(cntrl_s, (struct sockaddr *)&cntrl_addr, cntrl_len) < 0)
+ {
+ perror("bind Control socket");
+ daemon_shutdown(1);
+ }
+
+ chmod(DATA_AX25ROUTED_CTL_SOCK, 0600);
+ listen(cntrl_s, 1);
+
+ signal(SIGUSR1, sig_debug);
+ signal(SIGHUP, sig_reload);
+ signal(SIGTERM, sig_term);
+
+ cntrl_fd = -1;
+
+ for (;;)
+ {
+ fd_max = 0;
+ FD_ZERO(&fd_set);
+ FD_ZERO(&fd_set2);
+ FD_MAX(s);
+ if (cntrl_fd > 0)
+ {
+ FD_MAX(cntrl_fd);
+ FD_SET(cntrl_fd, &fd_set2);
+ } else {
+ FD_MAX(cntrl_s);
+ }
+
+ if (select(fd_max+1, &fd_set, NULL, &fd_set2, NULL) < 0)
+ {
+ if (errno == EINTR) /* woops! */
+ continue;
+
+ if (!FD_ISSET(cntrl_fd, &fd_set2))
+ {
+ perror("select");
+ save_cache();
+ daemon_shutdown(1);
+ } else {
+ close(cntrl_fd);
+ cntrl_fd = -1;
+ continue;
+ }
+ }
+
+ if (cntrl_fd > 0)
+ {
+ if (FD_ISSET(cntrl_fd, &fd_set))
+ {
+ size = read(cntrl_fd, buf, sizeof(buf));
+ if (size > 0)
+ {
+ buf[size] = '\0';
+ interpret_command(cntrl_fd, buf);
+ } else {
+ close(cntrl_fd);
+ cntrl_fd = -1;
+ }
+ }
+ } else
+ if (FD_ISSET(cntrl_s, &fd_set))
+ {
+ if ((cntrl_fd=accept(cntrl_s, (struct sockaddr *) &cntrl_addr, &cntrl_len)) < 0)
+ {
+ perror("accept Control");
+ save_cache();
+ daemon_shutdown(1);
+ }
+ }
+
+ if (reload)
+ reload_config();
+
+ if (FD_ISSET(s, &fd_set))
+ ax25_receive(s);
+ }
+
+ return 0; /* what ?! */
+}
diff --git a/ax25rtd/ax25rtd.conf b/ax25rtd/ax25rtd.conf
new file mode 100644
index 0000000..47111a9
--- /dev/null
+++ b/ax25rtd/ax25rtd.conf
@@ -0,0 +1,82 @@
+# Example configuration for ax25rtd. I'm assuming that you have a central
+# node with two interfaces serving the same subnet (this is my personal
+# setup).
+#
+# For a general discussion of each parameter see ax25rtd/README.
+#
+# General setup
+# =============
+#
+# The size of the caches. When the cache is full, the oldest entry
+# gets removed.
+#
+ax25-maxroutes 256
+ip-maxroutes 256
+#
+# Port config
+# ===========
+#
+# Note that you *must* specify the symbolic port
+# name as defined in axports, not the device names. Personally, I like
+# them to be identical.
+#
+# This is my 56kbps port (pi0a). It is the default interface and has a
+# static network route pointing to it. All users access this interface
+# directly and *not* via digipeaters.
+#
+[pi0a]
+#
+# Since all users access this interface directly, I don't need any
+# AX.25 routes here.
+#
+ax25-learn-routes no
+#
+# The internal cache should only learn from frames directed to me.
+#
+ax25-learn-only-mine yes
+#
+# Here you could specify a digipeater path added to every learned route
+# that has no digipeaters.
+#
+# ax25-add-path oe1xxx
+#
+# Since ax25rtd will learn only frames directed to the interface
+# callsign or one of our listeners we can specify additional mycalls.
+#
+# ax25-more-mycalls oe1xxx
+#
+# We already have a static network route to this interface and don't need
+# to learn any host route.
+#
+ip-learn-routes no
+#
+# I really don't like to change the mode.
+#
+ip-adjust-mode no
+#
+# ARP is correctly handled by the kernel on this interface (no digipeaters).
+#
+arp-add no
+#
+# Here is my second port (ax0). It is the "optional" interface. Any user
+# accessing my system on this interface causes the following entries to
+# be added:
+#
+# - IP host route
+# - ARP entry
+# - AX.25 route
+#
+# The nice feature is that the host route overrides the network route to
+# the default interface, allowing this setup to work. Note also that users
+# may access this interface via digipeaters.
+# If a user switches back to the default interface, the IP host route is
+# automatically deleted. The other entries remain, but this is not a
+# problem.
+#
+[ax0]
+#
+ax25-learn-routes yes
+ax24-learn-only-mine yes
+ip-learn-routes yes
+ip-adjust-mode no
+arp-add yes
diff --git a/ax25rtd/ax25rtd.h b/ax25rtd/ax25rtd.h
new file mode 100644
index 0000000..b45771f
--- /dev/null
+++ b/ax25rtd/ax25rtd.h
@@ -0,0 +1,163 @@
+/* $Id: ax25rtd.h,v 1.5 1997/06/05 18:54:57 oe1kib Exp oe1kib $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* Defines for defaults */
+
+#define IP_MAXROUTES 256
+#define AX25_MAXROUTES 256
+#define AX25_MAXCALLS 32
+
+/* Some AX.25 stuff */
+
+#define NEW_ARP 1
+#define NEW_ROUTE 2
+#define NEW_IPMODE 4
+
+#define SEG_FIRST 0x80
+#define SEG_REM 0x7F
+
+#define PID_SEGMENT 0x08
+#define PID_ARP 0xCD
+#define PID_IP 0xCC
+#define PID_NETROM 0xCF
+
+#define HDLCAEB 0x01
+#define SSSID_SPARE 0x40
+#define AX25_REPEATED 0x80
+
+#define LAPB_I 0x00
+#define LAPB_S 0x01
+#define LAPB_UI 0x03
+#define LAPB_PF 0x10
+
+#define ALEN 6
+#define AXLEN 7
+#define IPLEN 20
+
+
+/* structs for the caches */
+
+typedef struct ip_rt_entry_ {
+ struct ip_rt_entry_ *next, *prev;
+ unsigned long ip;
+ unsigned char iface[14];
+ ax25_address call;
+ char ipmode;
+ time_t timestamp;
+ char invalid;
+} ip_rt_entry;
+
+typedef struct ax25_rt_entry_ {
+ struct ax25_rt_entry_ *next, *prev;
+ unsigned char iface[14];
+ ax25_address call;
+ ax25_address digipeater[AX25_MAX_DIGIS];
+ int ndigi;
+ long cnt;
+ time_t timestamp;
+} ax25_rt_entry;
+
+/* struct for the channel configuration */
+
+typedef struct config_ {
+ struct config_ *next;
+ char port[128];
+ char dev[14];
+
+ char ax25_add_route;
+ char ax25_for_me;
+ char ax25_add_default;
+
+ char ip_add_route;
+ char ip_add_arp;
+ char ip_adjust_mode;
+ char ip_arp_use_netlink;
+
+ unsigned int dg_mtu;
+ unsigned int vc_mtu;
+ unsigned long tcp_irtt;
+
+ unsigned long netmask;
+ unsigned long ip;
+
+ int nmycalls;
+ ax25_address mycalls[AX25_MAXCALLS];
+
+ struct full_sockaddr_ax25 ax25_default_path;
+} config;
+
+/* global variables */
+
+extern const char * Version;
+
+extern int reload;
+
+extern config *Config;
+
+extern ip_rt_entry * ip_routes;
+extern int ip_routes_cnt;
+extern int ip_maxroutes;
+
+extern ax25_rt_entry * ax25_routes;
+extern int ax25_routes_cnt;
+extern int ax25_maxroutes;
+
+
+/* config.c */
+
+void load_config(void);
+void reload_config(void);
+void load_cache(void);
+void save_cache(void);
+void interpret_command(int fd, unsigned char *buf);
+
+/* listener.c */
+
+int call_is_mycall(config *config, ax25_address *call);
+int set_arp(config *config, long ip, ax25_address *call);
+int set_route(config *config, long ip);
+int set_ax25_route(config *config, ax25_rt_entry *rt);
+int set_ipmode(config *config, ax25_address *call, int ipmode);
+int del_kernel_ip_route(char *dev, long ip);
+int del_kernel_ax25_route(char *dev, ax25_address *call);
+void ax25_receive(int sock);
+
+/* ax25rtd.c */
+
+void daemon_shutdown(int reason);
+int set_ipmode(config *config, ax25_address *call, int ipmode);
+config * dev_get_config(char *dev);
+config * port_get_config(char *port);
+
+/* cache_dump.c */
+
+void dump_ip_routes(int fd, int cmd);
+void dump_ax25_routes(int fd, int cmd);
+void dump_config(int fd);
+
+/* cache_ctl.c */
+
+int update_ip_route(config *config, unsigned long ip, int ipmode, ax25_address *call, time_t timestamp);
+ax25_rt_entry * update_ax25_route(config *config, ax25_address *call, int ndigi, ax25_address *digi, time_t timestamp);
+int del_ip_route(unsigned long ip);
+int invalidate_ip_route(unsigned long ip);
+int del_ax25_route(config * config, ax25_address *call);
+void expire_ax25_route(time_t when);
+void expire_ip_route(time_t when);
diff --git a/ax25rtd/cache_ctl.c b/ax25rtd/cache_ctl.c
new file mode 100644
index 0000000..0d892ad
--- /dev/null
+++ b/ax25rtd/cache_ctl.c
@@ -0,0 +1,330 @@
+/* $Id: cache_ctl.c,v 1.4 1996/10/23 18:27:43 jreuter Exp jreuter $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+
+#include "ax25rtd.h"
+
+/* Hmm, we really should implement this in C++ */
+/* But I HATE it. */
+
+/* (later: haven't I seen this statement elsewere? hmm...) */
+
+int update_ip_route(config *config, unsigned long ip, int ipmode, ax25_address *call, time_t timestamp)
+{
+ ip_rt_entry *bp = ip_routes;
+ ip_rt_entry *bp_prev = ip_routes;
+ char *iface = config->dev;
+ int action = 0;
+
+ if (((ip ^ config->ip) & config->netmask) != 0)
+ return 0;
+
+ iface = config->dev;
+
+ while (bp)
+ {
+ if (bp->ip == ip)
+ {
+ if (bp->timestamp == 0 && timestamp != 0)
+ return 0;
+
+ if (strcmp(bp->iface, iface))
+ {
+ action |= NEW_ROUTE;
+ strcpy(bp->iface, iface);
+ }
+
+ if (memcmp(&bp->call, call, AXLEN))
+ {
+ action |= NEW_ARP;
+ memcpy(&bp->call, call, AXLEN);
+ }
+
+ if (ipmode && ipmode != bp->ipmode)
+ {
+ action |= NEW_IPMODE;
+ bp->ipmode = ipmode;
+ }
+
+ bp->timestamp = timestamp;
+
+ if (bp != ip_routes)
+ {
+ if (bp->next)
+ bp->next->prev = bp->prev;
+ if (bp->prev)
+ bp->prev->next = bp->next;
+
+ bp->next = ip_routes;
+ bp->prev = NULL;
+ ip_routes->prev = bp;
+ ip_routes = bp;
+ }
+
+ return action;
+ }
+
+ bp_prev = bp;
+ bp = bp->next;
+ }
+
+ if (ip_routes_cnt >= ip_maxroutes)
+ {
+ if (bp_prev == NULL) /* error */
+ return 0;
+
+ bp_prev->prev->next = NULL;
+ free(bp_prev);
+ ip_routes_cnt--;
+ }
+
+ bp = (ip_rt_entry *) malloc(sizeof(ip_rt_entry));
+ if (bp == NULL)
+ return 0;
+
+ ip_routes_cnt++;
+ action = NEW_ROUTE | NEW_ARP | NEW_IPMODE;
+ bp->ipmode = ipmode;
+ bp->ip = ip;
+ bp->invalid = 0;
+
+ bp->timestamp = timestamp;
+ strcpy(bp->iface, iface);
+ memcpy(&bp->call, call, AXLEN);
+
+ if (ip_routes == NULL)
+ {
+ ip_routes = bp;
+ bp->next = bp->prev = NULL;
+ return action;
+ }
+
+ bp->next = ip_routes;
+ bp->prev = NULL;
+ ip_routes->prev = bp;
+ ip_routes = bp;
+
+ return action;
+}
+
+
+ax25_rt_entry *update_ax25_route(config *config, ax25_address *call, int ndigi, ax25_address *digi, time_t timestamp)
+{
+ ax25_rt_entry *bp = ax25_routes;
+ ax25_rt_entry *bp_prev = ax25_routes;
+ unsigned char *iface = config->dev;
+ int action = 0;
+
+ while (bp)
+ {
+ if (!memcmp(call, &bp->call, AXLEN) && !strcmp(bp->iface, iface))
+ {
+ if (bp->timestamp == 0 && timestamp != 0)
+ return NULL;
+
+ if (ndigi != bp->ndigi || memcmp(bp->digipeater, digi, bp->ndigi*AXLEN))
+ {
+ action |= NEW_ROUTE;
+ memcpy(bp->digipeater, digi, ndigi*AXLEN);
+ bp->ndigi = ndigi;
+ }
+
+ bp->timestamp = timestamp;
+
+ if (bp != ax25_routes)
+ {
+ if (bp->next)
+ bp->next->prev = bp->prev;
+ if (bp->prev)
+ bp->prev->next = bp->next;
+
+ bp->next = ax25_routes;
+ bp->prev = NULL;
+ ax25_routes->prev = bp;
+ ax25_routes = bp;
+ }
+
+ if (action)
+ return bp;
+ else
+ return NULL;
+ }
+
+ bp_prev = bp;
+ bp = bp->next;
+ }
+
+ if (ax25_routes_cnt >= ax25_maxroutes)
+ {
+ if (bp_prev == NULL) /* error */
+ return NULL;
+
+ bp_prev->prev->next = NULL;
+ free(bp_prev);
+ ax25_routes_cnt--;
+ }
+
+ bp = (ax25_rt_entry *) malloc(sizeof(ax25_rt_entry));
+ if (bp == NULL)
+ return NULL;
+
+ ax25_routes_cnt++;
+
+ bp->timestamp = timestamp;
+ strcpy(bp->iface, iface);
+ bp->call = *call;
+
+ if (ndigi)
+ memcpy(bp->digipeater, digi, ndigi*AXLEN);
+
+ bp->ndigi = ndigi;
+
+ if (ax25_routes == NULL)
+ {
+ ax25_routes = bp;
+ bp->next = bp->prev = NULL;
+ return bp;
+ }
+
+ bp->next = ax25_routes;
+ bp->prev = NULL;
+ ax25_routes->prev = bp;
+ ax25_routes = bp;
+
+ return bp;
+}
+
+ip_rt_entry * remove_ip_route(ip_rt_entry *bp)
+{
+ ip_rt_entry *bp2;
+
+ bp2 = bp->next;
+ if (bp2)
+ bp2->prev = bp->prev;
+ if (bp->prev)
+ bp->prev->next = bp2;
+ if (bp == ip_routes)
+ ip_routes = bp2;
+
+ del_kernel_ip_route(bp->iface, bp->ip);
+
+ free(bp);
+ ip_routes_cnt--;
+ return bp2;
+}
+
+ax25_rt_entry * remove_ax25_route(ax25_rt_entry *bp)
+{
+ ax25_rt_entry *bp2;
+ ip_rt_entry *iprt;
+
+ bp2 = bp->next;
+ if (bp2)
+ bp2->prev = bp->prev;
+ if (bp->prev)
+ bp->prev->next = bp2;
+ if (bp == ax25_routes)
+ ax25_routes = bp2;
+
+ for (iprt = ip_routes; iprt; iprt = iprt->next)
+ if (!memcmp(&iprt->call, &bp->call, AXLEN))
+ remove_ip_route(iprt);
+
+ del_kernel_ax25_route(bp->iface, &bp->call);
+
+ free(bp);
+ ax25_routes_cnt--;
+ return bp2;
+}
+
+int del_ip_route(unsigned long ip)
+{
+ ip_rt_entry *bp;
+
+ if (ip == 0)
+ return 1;
+
+ for (bp=ip_routes; bp; bp = bp->next)
+ if (bp->ip == ip)
+ {
+ remove_ip_route(bp);
+ return 0;
+ }
+
+ return 1;
+}
+
+int invalidate_ip_route(unsigned long ip)
+{
+ ip_rt_entry *bp;
+
+ for (bp=ip_routes; bp; bp = bp->next)
+ if (bp->ip == ip)
+ {
+ bp->invalid = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+int del_ax25_route(config * config, ax25_address *call)
+{
+ ax25_rt_entry *bp;
+
+ for (bp=ax25_routes; bp; bp = bp->next)
+ if (!memcmp(call, &bp->call, AXLEN) && !strcmp(config->dev, bp->iface))
+ {
+ remove_ax25_route(bp);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void expire_ax25_route(time_t when)
+{
+ ax25_rt_entry *bp;
+ time_t now = time(NULL);
+
+ for (bp = ax25_routes; bp; )
+ if (bp->timestamp != 0 && bp->timestamp+when <= now)
+ bp = remove_ax25_route(bp);
+ else
+ bp = bp->next;
+}
+
+void expire_ip_route(time_t when)
+{
+ ip_rt_entry *bp;
+ time_t now = time(NULL);
+
+ for (bp = ip_routes; bp; )
+ if (bp->timestamp != 0 && bp->timestamp+when <= now)
+ bp = remove_ip_route(bp);
+ else
+ bp = bp->next;
+}
diff --git a/ax25rtd/cache_dump.c b/ax25rtd/cache_dump.c
new file mode 100644
index 0000000..93b211e
--- /dev/null
+++ b/ax25rtd/cache_dump.c
@@ -0,0 +1,141 @@
+/* $Id: cache_dump.c,v 1.5 1996/10/23 18:27:43 jreuter Exp jreuter $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+
+#include "ax25rtd.h"
+
+void dump_ip_routes(int fd, int cmd)
+{
+ ip_rt_entry *bp;
+ config *config;
+ char buf[256], *dev;
+ unsigned long ip;
+ int len;
+
+ for (bp = ip_routes; bp; bp = bp->next)
+ {
+ ip = htonl(bp->ip);
+
+ if (cmd)
+ {
+ len = sprintf(buf, "add ip ");
+ dev = bp->iface;
+ } else {
+ len = 0;
+ config = dev_get_config(bp->iface);
+ if (config != NULL)
+ dev = config->port;
+ else
+ dev = bp->iface;
+ }
+
+ len += sprintf(buf+len, "%d.%d.%d.%d",
+ (int) ((ip & 0xFF000000) >> 24),
+ (int) ((ip & 0x00FF0000) >> 16),
+ (int) ((ip & 0x0000FF00) >> 8),
+ (int) (ip & 0x000000FF));
+
+ len += sprintf(buf+len, " %-4s %8.8lx %-9s ", dev, bp->timestamp, ax25_ntoa(&bp->call));
+ if (bp->invalid)
+ len += sprintf(buf+len, "X\n");
+ else
+ len += sprintf(buf+len, "%c\n", bp->ipmode? 'v':'d');
+
+ write(fd, buf, len);
+ }
+
+ if (!cmd)
+ write(fd, ".\n", 2);
+
+}
+
+void dump_ax25_routes(int fd, int cmd)
+{
+ ax25_rt_entry *bp;
+ config *config;
+ char buf[256], *dev;
+ int k, len;
+
+ for (bp = ax25_routes; bp; bp = bp->next)
+ {
+ if (cmd)
+ {
+ len = sprintf(buf, "add ax25 ");
+ dev = bp->iface;
+ } else {
+ len = 0;
+ config = dev_get_config(bp->iface);
+ if (config != NULL)
+ dev = config->port;
+ else
+ dev = bp->iface;
+ }
+
+ len += sprintf(buf+len, "%-9s %-4s %8.8lx", ax25_ntoa(&bp->call), dev, bp->timestamp);
+
+ for (k = 0; k < bp->ndigi; k++)
+ len += sprintf(buf+len, " %s", ax25_ntoa(&bp->digipeater[k]));
+ len += sprintf(buf+len, "\n");
+ write(fd, buf, len);
+ }
+
+ if (!cmd)
+ write(fd, ".\n", 2);
+}
+
+void dump_config(int fd)
+{
+ config *config;
+ int k;
+
+ fprintf(stderr, "config:\n");
+ for (config = Config; config; config = config->next)
+ {
+ fprintf(stderr, "Device = %s\n", config->dev);
+ fprintf(stderr, "Port = %s\n", config->port);
+ fprintf(stderr, "ax25_add_route = %d\n", config->ax25_add_route);
+ fprintf(stderr, "ax25_for_me = %d\n", config->ax25_for_me);
+ fprintf(stderr, "ax25_add_default = %d\n", config->ax25_add_default);
+ fprintf(stderr, "ip_add_route = %d\n", config->ip_add_route);
+ fprintf(stderr, "ip_add_arp = %d\n", config->ip_add_arp);
+ fprintf(stderr, "ip_adjust_mode = %d\n", config->ip_adjust_mode);
+ fprintf(stderr, "netmask = %8.8lx\n", config->netmask);
+ fprintf(stderr, "ip = %8.8lx\n", config->ip);
+ fprintf(stderr, "nmycalls = %d\n", config->nmycalls);
+ fprintf(stderr, "calls =");
+ for (k = 0; k < config->nmycalls; k++)
+ fprintf(stderr, " %s", ax25_ntoa(&config->mycalls[k]));
+ fprintf(stderr, "\n");
+ fprintf(stderr, "ax25_default_path=");
+ for (k = 0; k < config->ax25_default_path.fsa_ax25.sax25_ndigis; k++)
+ fprintf(stderr, " %s", ax25_ntoa(&config->ax25_default_path.fsa_digipeater[k]));
+ fprintf(stderr, "\n.\n");
+ }
+}
diff --git a/ax25rtd/config.c b/ax25rtd/config.c
new file mode 100644
index 0000000..1306d2a
--- /dev/null
+++ b/ax25rtd/config.c
@@ -0,0 +1,736 @@
+/* $Id: config.c,v 1.7 1997/06/05 18:55:51 oe1kib Exp oe1kib $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+
+#include "../pathnames.h"
+#include "ax25rtd.h"
+
+ax25_address *asc2ax(char *call)
+{
+ static ax25_address callsign;
+
+ ax25_aton_entry(call, (char *)&callsign);
+
+ return &callsign;
+}
+
+static long asc2ip(char *s)
+{
+ struct in_addr addr;
+
+ if (!inet_aton(s, &addr))
+ return 0;
+
+ return addr.s_addr;
+}
+
+
+char * prepare_cmdline(char *buf)
+{
+ char *p;
+ for (p = buf; *p; p++)
+ {
+ if (*p == '\t') *p = ' ';
+ *p = tolower(*p);
+
+ if (*p == '\n')
+ {
+ *p = '\0';
+ break;
+ }
+
+ if (*p == '#')
+ {
+ *p = '\0';
+ break;
+ }
+ }
+
+ return buf;
+}
+
+char * get_next_arg(char **p)
+{
+ char *p2;
+
+ if (p == NULL || *p == NULL)
+ return NULL;
+
+ p2 = *p;
+ for (; *p2 && *p2 == ' '; p2++) ;
+ if (!*p2)
+ return NULL;
+
+ *p = strchr(p2, ' ');
+ if (*p != NULL)
+ {
+ **p = '\0';
+ (*p)++;
+ }
+
+ return p2;
+}
+
+static inline void invalid_arg(char *c, char *p)
+{
+ fprintf(stderr, "%s: invalid argument %s\n", c, p);
+}
+
+static inline void missing_arg(char *c)
+{
+ fprintf(stderr, "%s: argument missing\n", c);
+}
+
+static int yesno(char *arg)
+{
+ if (!arg)
+ return 0;
+ if (!strcmp(arg, "yes") || !strcmp(arg, "1"))
+ return 1;
+ if (!strcmp(arg, "no") || !strcmp(arg, "0"))
+ return 0;
+ return -1;
+}
+
+static ax25_address *get_mycall(char *port)
+{
+ char *addr;
+
+ if ((addr = ax25_config_get_addr(port)) == NULL)
+ return NULL;
+
+ return asc2ax(addr);
+}
+
+
+void load_ports(void)
+{
+ config *config, *cfg, *ncfg;
+ char buf[1024];
+ struct ifconf ifc;
+ struct ifreq ifr, *ifrp;
+ int k, fd;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ fprintf(stderr, "Unable to open socket\n");
+ exit(1);
+ }
+
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
+ {
+ fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
+ return;
+ }
+
+ ifrp = ifc.ifc_req;
+ for (k = ifc.ifc_len / sizeof(struct ifreq); k > 0; k--, ifrp++)
+ {
+ strcpy(ifr.ifr_name, ifrp->ifr_name);
+ if (strcmp(ifr.ifr_name, "lo") == 0) continue;
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
+ {
+ fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (!(ifr.ifr_flags & IFF_UP)) continue;
+
+ ioctl(fd, SIOCGIFHWADDR, &ifr);
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_AX25)
+ continue;
+
+ for (config = Config; config; config = config->next)
+ if (!memcmp(&config->mycalls[0], ifr.ifr_hwaddr.sa_data, AXLEN) && !*config->dev)
+ {
+ strcpy(config->dev, ifr.ifr_name);
+ ioctl(fd, SIOCGIFADDR, &ifr);
+ config->ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
+ strcpy(ifr.ifr_name, config->dev);
+ ioctl(fd, SIOCGIFNETMASK, &ifr);
+ config->netmask = ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr;
+ break;
+ }
+ }
+ close(fd);
+
+ config = cfg = Config;
+
+ while(config)
+ {
+ if (!*config->dev)
+ {
+ if (config == Config)
+ {
+ Config = config->next;
+ cfg = Config;
+ } else
+ cfg->next = config->next;
+ ncfg = config->next;
+ free(config);
+ config = ncfg;
+ } else {
+ cfg = config;
+ config = config->next;
+ }
+ }
+}
+
+void load_listeners(void)
+{
+ config *config;
+ char buf[1024], device[14], call[10], dcall[10];
+ int k;
+ FILE *fp;
+ ax25_address *axcall;
+
+
+ fp = fopen(PROC_AX25_FILE, "r");
+
+ if (fp == NULL)
+ {
+ fprintf(stderr, "No AX.25 in kernel. Tss, tss...\n");
+ exit(1);
+ }
+
+ while (fgets(buf, sizeof(buf)-1, fp) != NULL)
+ {
+ k = sscanf(buf, "%s %s %s", dcall, call, device);
+ if (k == 3 && !strcmp(dcall, "*"))
+ {
+ axcall = asc2ax(call);
+ if (!strcmp("???", device))
+ {
+ for (config = Config; config; config = config->next)
+ {
+ if (call_is_mycall(config, axcall) || config->nmycalls > AX25_MAXCALLS)
+ continue;
+ memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN);
+ }
+ } else {
+ config = dev_get_config(device);
+ if (config == NULL || call_is_mycall(config, axcall) || config->nmycalls > AX25_MAXCALLS)
+ continue;
+
+ memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+void load_config()
+{
+ FILE *fp;
+ char buf[1024], *p, *cmd, *arg;
+ config *config, *cfg;
+ ax25_address *axcall;
+
+ config = NULL;
+
+ fp = fopen(CONF_AX25ROUTED_FILE, "r");
+
+ if (fp == NULL)
+ {
+ fprintf(stderr, "config file %s not found\n", CONF_AX25ROUTED_FILE);
+ exit(1);
+ }
+
+ while(fgets(buf, sizeof(buf)-1, fp) != NULL)
+ {
+ p = prepare_cmdline(buf);
+ if (!*p)
+ continue;
+
+ cmd = get_next_arg(&p);
+ if (cmd == NULL)
+ continue;
+ arg = get_next_arg(&p);
+
+ if (*cmd == '[')
+ {
+ cmd++;
+ p = strrchr(cmd, ']');
+ if (p == NULL)
+ {
+ fprintf(stderr, "syntax error: [%s\n", cmd);
+ continue;
+ }
+ *p = '\0';
+
+ axcall = get_mycall(cmd);
+ if (axcall == NULL)
+ continue;
+
+ cfg = (struct config_ *) malloc(sizeof(struct config_));
+ if (cfg == NULL)
+ {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ memset(cfg, 0, sizeof(struct config_));
+
+ if (config)
+ config->next = cfg;
+ else
+ Config = cfg;
+
+ cfg->next = NULL;
+ config = cfg;
+ strcpy(config->port, cmd);
+ memcpy(&config->mycalls[0], axcall, AXLEN);
+ config->nmycalls = 1;
+ } else
+ if (config && !strcmp(cmd, "ax25-learn-routes"))
+ {
+ /* ax25-learn-routes no|yes: learn digipeater path */
+ if (arg)
+ {
+ int k = yesno(arg);
+
+ if (k == -1)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->ax25_add_route = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "ax25-learn-only-mine"))
+ {
+ /* ax25-learn-only-mine no|yes: learn only if addressed to me */
+ if (arg)
+ {
+ int k = yesno(arg);
+
+ if (k == -1)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->ax25_for_me = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "ax25-add-path"))
+ {
+ /* ax25-add-path [no|<digis>]: add digis if digi-less frame rvd */
+ int k = 0;
+ if (!arg || (arg && yesno(arg) == 0))
+ continue;
+
+ config->ax25_add_default = 1;
+ while (arg && k < AX25_MAX_DIGIS)
+ {
+ memcpy(&config->ax25_default_path.fsa_digipeater[k], asc2ax(arg), AXLEN);
+ arg = get_next_arg(&p);
+ k++;
+ }
+ config->ax25_default_path.fsa_ax25.sax25_ndigis = k;
+ } else
+ if (config && !strcmp(cmd, "ax25-more-mycalls"))
+ {
+ /* ax25-more-mycalls call1 call2: frames to this calls are for "me", too. */
+ if (arg)
+ {
+ while(arg && config->nmycalls < AX25_MAXCALLS)
+ {
+ axcall = asc2ax(arg);
+ if (call_is_mycall(config, axcall))
+ continue;
+ memcpy(&config->mycalls[config->nmycalls++], axcall, AXLEN);
+ arg = get_next_arg(&p);
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "ip-learn-routes"))
+ {
+ /* ip-learn-routes no|yes: learn ip routes */
+ if (arg)
+ {
+ int k = yesno(arg);
+
+ if (k == -1)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->ip_add_route = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "irtt"))
+ {
+ /* irtt <irtt>: new routes will get this IRTT in msec */
+ if (arg)
+ {
+ int k = atoi(arg);
+
+ if (k == 0)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->tcp_irtt = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "dg-mtu"))
+ {
+ /* dg-mtu <mtu>: MTU for datagram mode routes (unused) */
+ if (arg)
+ {
+ int k = atoi(arg);
+
+ if (k == 0)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->dg_mtu = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "vc-mtu"))
+ {
+ /* vc-mtu <mtu>: MTU for virtual connect mode routes (unused) */
+ if (arg)
+ {
+ int k = atoi(arg);
+
+ if (k == 0)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->vc_mtu = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "ip-adjust-mode"))
+ {
+ /* ip-adjust-mode no|yes: adjust ip-mode? (dg or vc) */
+ if (arg)
+ {
+ int k = yesno(arg);
+
+ if (k == -1)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->ip_adjust_mode = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (config && !strcmp(cmd, "arp-add"))
+ {
+ /* arp-add no|yes: adjust arp table? */
+ if (arg)
+ {
+ int k = yesno(arg);
+
+ if (k == -1)
+ {
+ invalid_arg(cmd, arg);
+ continue;
+ } else {
+ config->ip_add_arp = k;
+ }
+ } else
+ missing_arg(cmd);
+ } else
+ if (!strcmp(cmd, "ax25-maxroutes"))
+ {
+ if (arg)
+ ax25_maxroutes = atoi(arg);
+ else
+ missing_arg(cmd);
+ } else
+ if (!strcmp(cmd, "ip-maxroutes"))
+ {
+ if (arg)
+ ax25_maxroutes = atoi(arg);
+ else
+ missing_arg(cmd);
+
+ } else
+ fprintf(stderr, "invalid command %s\n", cmd);
+ }
+ fclose(fp);
+
+ load_ports();
+ load_listeners();
+
+ reload = 0;
+}
+
+void reload_config(void)
+{
+ config *cfg, *config = Config;
+
+ while(config)
+ {
+ cfg = config->next;
+ free(config);
+ config = cfg;
+ }
+ Config = NULL;
+
+ load_config();
+}
+
+
+/* commands:
+ ---------
+
+ add ax25 <callsign> <dev> <time> [<digipeater>] # Add an AX.25 route
+ add ip <ip> <dev> <time> <call> <mode> # Add an IP route & mode
+ del ax25 <callsign> <dev> # Remove an AX.25 route (from cache)
+ del ip <ip> # Remove an IP route (from cache)
+ list [ax25|ip] # List cache entries
+ reload # Reload config
+ save # Save cache
+ expire <minutes> # Expire cache entries
+ shutdown # Save cache and exit
+
+ There's a difference between 'list heard' and 'heard':
+
+ The 'list' commands will output the symbolic port names as defined in
+ /usr/local/etc/axports (i.e. 9k6 for scc3), while 'heard' shows the
+ 'real' network device name (i.e. scc3). All commands accept either the
+ port or the network device name. The expample
+
+ add ax25 dl0tha scc3 0 db0pra
+
+ is equivalent to
+
+ add ax25 dl0tha 9k6 0 dbpra
+
+ Note that in conflicting cases the network device name has precedence
+ over the port name.
+*/
+
+
+void interpret_command(int fd, unsigned char *buf)
+{
+ char *p, *cmd, *arg, *arg2, *dev, *time;
+ ax25_address digipeater[AX25_MAX_DIGIS];
+ ax25_rt_entry *ax25rt;
+ int ndigi, ipmode, action;
+ time_t stamp;
+ config *config;
+ long ip;
+
+ p = prepare_cmdline(buf);
+
+ if (!*p) return;
+
+ cmd = get_next_arg(&p);
+ arg = get_next_arg(&p);
+
+ if (!strcmp(cmd, "add"))
+ {
+ if (arg == NULL)
+ return;
+ if ((arg2 = get_next_arg(&p)) == NULL)
+ return;
+ if ( (dev = get_next_arg(&p)) == NULL)
+ return;
+ if ( (time = get_next_arg(&p)) == NULL)
+ return;
+ if ( (config = dev_get_config(dev)) == NULL)
+ return;
+
+ sscanf(time, "%lx", &stamp);
+
+ if (!strcmp(arg, "ax25"))
+ {
+ ndigi = 0;
+ arg = get_next_arg(&p);
+
+ while (arg != NULL)
+ {
+ memcpy(&digipeater[ndigi++], asc2ax(arg), AXLEN);
+ if (ndigi == AX25_MAX_DIGIS)
+ break;
+ arg = get_next_arg(&p);
+ }
+
+ ax25rt = update_ax25_route(config, asc2ax(arg2), ndigi, digipeater, stamp);
+ if (ax25rt != NULL)
+ set_ax25_route(config, ax25rt);
+ } else
+ if (!strcmp(arg, "ip"))
+ {
+ ip = asc2ip(arg2);
+
+ if ((arg2 = get_next_arg(&p)) == NULL)
+ return;
+
+ if ((arg = get_next_arg(&p)) == NULL)
+ return;
+
+ if (*arg == 'x')
+ return;
+
+ ipmode = (*arg == 'v');
+
+ action = update_ip_route(config, ip, ipmode, asc2ax(arg2), stamp);
+
+ if (action & NEW_ROUTE)
+ if (set_route(config, ip))
+ return;
+
+ if (action & NEW_ARP)
+ if (set_arp(config, ip, asc2ax(arg2)))
+ return;
+
+ if (action & NEW_IPMODE)
+ if (set_ipmode(config, asc2ax(arg2), ipmode))
+ return;
+ }
+ } else if (!strcmp(cmd, "del"))
+ {
+ if (arg == NULL)
+ return;
+ arg2 = get_next_arg(&p);
+ if (arg2 == NULL)
+ return;
+
+ if (!strcmp(arg, "ax25"))
+ {
+ arg = get_next_arg(&p);
+ if (arg == NULL || (config = dev_get_config(arg)) == NULL)
+ return;
+ del_ax25_route(config, asc2ax(arg2));
+ } else
+ if (!strcmp(arg, "ip"))
+ {
+ del_ip_route(asc2ip(arg2));
+ }
+ } else if (!strcmp(cmd, "expire"))
+ {
+ if (arg == NULL)
+ return;
+ sscanf(arg, "%ld", &stamp);
+ if (stamp != 0)
+ {
+ stamp*=60;
+ expire_ax25_route(stamp);
+ expire_ip_route(stamp);
+ }
+ } else if (!strcmp(cmd, "reload"))
+ {
+ reload_config();
+ } else if (!strcmp(cmd, "list"))
+ {
+ if (arg == NULL)
+ return;
+
+ if (!strcmp(arg, "ax25"))
+ dump_ax25_routes(fd, 0);
+ else
+ if (!strcmp(arg, "ip"))
+ dump_ip_routes(fd, 0);
+ } else if (!strcmp(cmd, "shutdown"))
+ {
+ save_cache();
+ daemon_shutdown(0);
+ } else if (!strcmp(cmd, "save"))
+ {
+ save_cache();
+ } else if (!strcmp(cmd, "version"))
+ {
+ char buf[256];
+ sprintf(buf, "%s\n", Version);
+ write(fd, buf, strlen(buf));
+ } else if (!strcmp(cmd, "quit"))
+ {
+ close(fd);
+ }
+}
+
+void load_cache(void)
+{
+ FILE *fp;
+ char buf[512];
+
+ fp = fopen(DATA_AX25ROUTED_AXRT_FILE, "r");
+ if (fp != NULL)
+ {
+ while(fgets(buf, sizeof(buf), fp) != NULL)
+ interpret_command(2, buf);
+ }
+ fclose(fp);
+
+ fp = fopen(DATA_AX25ROUTED_IPRT_FILE, "r");
+ if (fp != NULL)
+ {
+ while(fgets(buf, sizeof(buf), fp) != NULL)
+ interpret_command(2, buf);
+ }
+ fclose(fp);
+}
+
+void save_cache(void)
+{
+ int fd;
+
+ fd = creat(DATA_AX25ROUTED_AXRT_FILE, 0664);
+ dump_ax25_routes(fd, 1);
+ close(fd);
+
+ fd = creat(DATA_AX25ROUTED_IPRT_FILE, 0664);
+ dump_ip_routes(fd, 1);
+ close(fd);
+
+}
diff --git a/ax25rtd/listener.c b/ax25rtd/listener.c
new file mode 100644
index 0000000..27b8622
--- /dev/null
+++ b/ax25rtd/listener.c
@@ -0,0 +1,579 @@
+/* $Id: listener.c,v 1.9 1997/06/05 18:56:08 oe1kib Exp oe1kib $
+ *
+ * Copyright (c) 1996 Jörg Reuter (jreuter@poboxes.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+ /* TODO: Should add partial path to ax25_route if we are one of the
+ * digipeaters.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netax25/ax25.h>
+
+#include "../pathnames.h"
+#include "ax25rtd.h"
+
+
+/* FIXME */
+static unsigned long get_from_arp(unsigned char *data, int size)
+{
+ if (size < 16)
+ return 0;
+
+ return ntohl(0);
+}
+
+static unsigned long get_from_ip(unsigned char *data, int size)
+{
+ unsigned long adr;
+
+ if ((*data & 0xf)*4 < IPLEN)
+ return 0;
+
+ adr = data[12] << 24; /* NETWORK byte order */
+ adr += data[13] << 16;
+ adr += data[14] << 8;
+ adr += data[15];
+
+ return ntohl(adr); /* HOST byte order */
+}
+
+int call_is_mycall(config *config, ax25_address *call)
+{
+ int k;
+
+ for (k = 0; k < config->nmycalls; k++)
+ if (!memcmp(call, &config->mycalls[k], AXLEN))
+ return 1;
+ return 0;
+}
+
+/*
+ * This catches *all* invalid callsigns, unlike ax25validate.
+ */
+
+static int check_ax25_addr(unsigned char *buf)
+{
+ int k;
+ unsigned char c;
+
+ /* must start with at least one capital letter or digit */
+ for (k=0; k < 6; k++) {
+ c = buf[k] >> 1;
+ if (c == ' ') break;
+ if ((c < 'A' || c > 'Z') && (c < '0' || c > '9'))
+ return 1;
+ }
+
+ /* NULL address is invalid */
+ if (k == 0)
+ return 1;
+
+ /* remaining fields must consist of spaces only */
+ for (k++; k < 6; k++)
+ if (buf[k] >> 1 != ' ')
+ return 1;
+
+ return 0;
+}
+
+static inline void invert_digipeater_path(ax25_address *digipeater, int ndigi)
+{
+ int k, m;
+ ax25_address fdigi;
+
+ if (ndigi == 0)
+ return;
+
+ ndigi--;
+
+ memcpy(&fdigi, &digipeater[0], AXLEN);
+
+ for (m = 0,k = ndigi; k > 0; k--, m++)
+ memcpy(&digipeater[m], &digipeater[k], AXLEN);
+
+ memcpy(&digipeater[ndigi], &fdigi, AXLEN);
+}
+
+int set_arp(config *config, long ip, ax25_address *call)
+{
+ struct sockaddr_in *isa;
+ struct sockaddr_ax25 *asa;
+ struct arpreq arp;
+ int fds;
+
+ if (!config->ip_add_arp)
+ return 0;
+
+ fds = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset((char *) &arp, 0, sizeof(arp));
+
+ isa = (struct sockaddr_in *) &arp.arp_pa;
+ asa = (struct sockaddr_ax25 *) &arp.arp_ha;
+
+ isa->sin_family = AF_INET;
+ isa->sin_port = 0;
+ isa->sin_addr.s_addr = ip;
+
+ asa->sax25_family = AF_AX25;
+ asa->sax25_ndigis = 0;
+ asa->sax25_call = *call;
+
+ arp.arp_flags = ATF_PERM | ATF_COM;
+ strcpy(arp.arp_dev, config->dev);
+
+ if (ioctl(fds, SIOCSARP, &arp) < 0)
+ {
+ invalidate_ip_route(ip);
+ perror("routspy: SIOCSARP");
+ close(fds);
+ return 1;
+ }
+ close(fds);
+ return 0;
+}
+
+int set_route(config *config, long ip)
+{
+ struct rtentry rt;
+ struct sockaddr_in *isa;
+ char origdev[16], buf[1024];
+ long ipr;
+ int fds;
+ FILE *fp;
+
+ fp = fopen(PROC_IP_ROUTE_FILE, "r");
+ if (fp == NULL)
+ {
+ invalidate_ip_route(ip);
+ return 1;
+ }
+
+ fgets(buf, sizeof(buf)-1, fp); /* discard header */
+ while (fgets(buf, sizeof(buf)-1, fp) != NULL)
+ {
+ sscanf(buf, "%s %lx", origdev, &ipr);
+ if (ipr == ip)
+ {
+ if (dev_get_config(origdev) == NULL)
+ {
+ invalidate_ip_route(ip);
+ fclose(fp);
+ return 1;
+ }
+ else
+ {
+ del_kernel_ip_route(origdev, ip);
+ }
+ }
+
+ }
+ fclose(fp);
+
+ if (!config->ip_add_route)
+ return 0;
+
+ fds = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset((char *) &rt, 0, sizeof(rt));
+
+ isa = (struct sockaddr_in *) &rt.rt_dst;
+
+ isa->sin_family = AF_INET;
+ isa->sin_port = 0;
+ isa->sin_addr.s_addr = ip;
+
+ rt.rt_flags = RTF_UP | RTF_HOST;
+ rt.rt_dev = config->dev;
+
+ if (config->tcp_irtt != 0)
+ {
+ rt.rt_irtt = config->tcp_irtt;
+ rt.rt_flags |= RTF_IRTT;
+ }
+
+ isa = (struct sockaddr_in *) &rt.rt_genmask;
+ isa->sin_addr.s_addr = 0xffffffff;
+
+ if (ioctl(fds, SIOCADDRT, &rt) < 0)
+ {
+ invalidate_ip_route(ip);
+ perror("ax25rtd: IP SIOCADDRT");
+ close(fds);
+ return 1;
+ }
+ close(fds);
+ return 0;
+}
+
+int del_kernel_ip_route(char *dev, long ip)
+{
+ int fds;
+ struct rtentry rt;
+ struct sockaddr_in *isa;
+ config *config;
+
+ config = dev_get_config(dev);
+ if (config == NULL || !config->ip_add_route)
+ return 0;
+
+ fds = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset((char *) &rt, 0, sizeof(struct rtentry));
+
+ isa = (struct sockaddr_in *) &rt.rt_dst;
+
+ isa->sin_family = AF_INET;
+ isa->sin_addr.s_addr = ip;
+
+ rt.rt_flags = RTF_UP | RTF_HOST;
+ rt.rt_dev = dev;
+
+ if (ioctl(fds, SIOCDELRT, &rt) < 0)
+ {
+ perror("ax25rtd: IP SIOCDELRT");
+ close(fds);
+ return 1;
+ }
+ close(fds);
+ return 0;
+}
+
+int set_ax25_route(config *config, ax25_rt_entry *rt)
+{
+ struct ax25_routes_struct ax25_route;
+ int fds, k;
+
+ if (!config->ax25_add_route)
+ return 0;
+
+ ax25_route.port_addr = config->mycalls[0];
+ ax25_route.dest_addr = rt->call;
+ ax25_route.digi_count = rt->ndigi;
+
+ for (k = 0; k < rt->ndigi; k++)
+ ax25_route.digi_addr[k] = rt->digipeater[k];
+
+ fds = socket(AF_AX25, SOCK_SEQPACKET, 0);
+
+ if (ioctl(fds, SIOCADDRT, &ax25_route) < 0)
+ {
+ perror("ax25rtd: AX.25 SIOCADDRT");
+ close(fds);
+ return 1;
+ }
+
+ close(fds);
+ return 0;
+}
+
+int del_kernel_ax25_route(char *dev, ax25_address *call)
+{
+ struct ax25_routes_struct ax25_route;
+ int fds;
+ config *config;
+
+ config = dev_get_config(dev);
+ if (config == NULL || !config->ax25_add_route)
+ return 0;
+
+ ax25_route.port_addr = config->mycalls[0];
+ ax25_route.dest_addr = *call;
+
+ fds = socket(AF_AX25, SOCK_SEQPACKET, 0);
+
+ if (ioctl(fds, SIOCDELRT, &ax25_route) < 0)
+ {
+ perror("ax25rtd: AX.25 SIOCDELRT");
+ close(fds);
+ return 1;
+ }
+
+ close(fds);
+ return 0;
+}
+
+int set_ipmode(config *config, ax25_address *call, int ipmode)
+{
+ struct ax25_route_opt_struct ax25_opt;
+ int fds;
+
+ if (!config->ip_adjust_mode)
+ return 0;
+
+ ax25_opt.port_addr = config->mycalls[0];
+ ax25_opt.dest_addr = *call;
+ ax25_opt.cmd = AX25_SET_RT_IPMODE;
+ ax25_opt.arg = ipmode? 'V':'C';
+
+ fds = socket(AF_AX25, SOCK_SEQPACKET, 0);
+
+ if (ioctl(fds, SIOCAX25OPTRT, &ax25_opt) < 0)
+ {
+ perror("ax25rtd: SIOCAX25OPTRT");
+ close(fds);
+ return 1;
+ }
+
+ close(fds);
+ return 0;
+
+}
+
+/* Yes, the code *IS* ugly... */
+
+#define SKIP(o) {data+=(o); size-=(o);}
+void ax25_receive(int sock)
+{
+ unsigned char buf[1500];
+ unsigned char *data;
+ unsigned long ip;
+ struct sockaddr sa;
+ ax25_address srccall, destcall, digipeater[AX25_MAX_DIGIS];
+ char extseq = 0;
+ int size, asize, action, ipmode, ctl, pid, ndigi, kdigi, mine;
+ time_t stamp;
+ config *config;
+ ax25_rt_entry * ax25rt;
+
+ asize = sizeof(sa);
+ if ((size = recvfrom(sock, buf, sizeof(buf), 0, &sa, &asize)) < 0)
+ {
+ perror("recvfrom");
+ save_cache();
+ daemon_shutdown(1);
+ }
+
+ stamp = time(NULL);
+ ip = 0;
+ pid = ctl = 0;
+
+ config = dev_get_config(sa.sa_data);
+
+ if (config == NULL)
+ return;
+
+ data = buf;
+
+ /*
+ * KISS data?
+ */
+
+ if (*data != 0)
+ return;
+
+ SKIP(1);
+
+ /* valid frame? */
+
+ if (size < (2*AXLEN+1))
+ return;
+
+ /*
+ * Get destination callsign
+ */
+
+ if (check_ax25_addr(data))
+ return;
+
+ memcpy(&destcall, data, AXLEN);
+ destcall.ax25_call[6] &= 0x1e;
+ SKIP(AXLEN);
+
+ mine = call_is_mycall(config, &destcall);
+
+ /*
+ * Get Source callsign
+ */
+
+ if (check_ax25_addr(data))
+ return;
+
+ memcpy(&srccall, data, AXLEN);
+ srccall.ax25_call[6] &= 0x1e;
+ SKIP(ALEN);
+
+ /*
+ * How long is our control field?
+ */
+
+ extseq = ~(*data) & SSSID_SPARE;
+
+ /*
+ * Extract digipeaters
+ */
+
+ ndigi = 0;
+ while (((*data) & HDLCAEB) != HDLCAEB)
+ {
+ SKIP(1);
+ if (size <= 0 || check_ax25_addr(data))
+ return;
+
+ if (ndigi < AX25_MAX_DIGIS)
+ memcpy(&digipeater[ndigi++], data, AXLEN);
+ else
+ return;
+
+
+ SKIP(ALEN);
+ }
+
+ SKIP(1);
+ if (size <= 0)
+ return;
+
+ /*
+ * Get type of frame
+ */
+
+ if ((*data & LAPB_S) == LAPB_I)
+ ctl = LAPB_I;
+ else
+ {
+ ctl = *data;
+ if (extseq == 0)
+ ctl &= ~LAPB_PF;
+ }
+
+ /*
+ * Check if info frame and get PID
+ */
+
+ if (ctl == LAPB_I || ctl == LAPB_UI)
+ {
+ SKIP(extseq? 2:1);
+ if (size <= 0)
+ return;
+
+ /* Get PID */
+
+ pid = *data;
+
+ if (pid == PID_SEGMENT)
+ {
+ SKIP(1);
+ if (size <= 0)
+ return;
+ pid = 0;
+
+ if (*data && SEG_FIRST)
+ {
+ pid = *data;
+ SKIP(1);
+ if (size <= 0)
+ return;
+ }
+ }
+ }
+
+ /*
+ * See if it is fully digipeated (TODO: or if we are the next digipeater)
+ */
+
+ for (kdigi = 0; kdigi < ndigi; kdigi++)
+ {
+ if ((digipeater[kdigi].ax25_call[6] & AX25_REPEATED) != AX25_REPEATED)
+ return;
+
+ digipeater[kdigi].ax25_call[6] &= 0x1e;
+ }
+
+ invert_digipeater_path(digipeater, ndigi);
+
+ /*
+ * Are we allowed to add it to our routing table?
+ */
+
+ if (mine || !config->ax25_for_me)
+ {
+ if (!mine && ndigi == 0 && config->ax25_add_default)
+ {
+ ndigi = config->ax25_default_path.fsa_ax25.sax25_ndigis;
+ for (kdigi = 0; kdigi < ndigi; kdigi++)
+ if (!memcmp(&srccall, &config->ax25_default_path.fsa_digipeater[kdigi], AXLEN))
+ break;
+
+ if (ndigi == kdigi)
+ memcpy(digipeater, config->ax25_default_path.fsa_digipeater, ndigi*AXLEN);
+ else
+ ndigi = 0;
+ }
+
+ ax25rt = update_ax25_route(config, &srccall, ndigi, digipeater, stamp);
+
+ if (ax25rt != NULL)
+ set_ax25_route(config, ax25rt);
+ }
+
+ /*
+ * Now see if it carries IP traffic
+ */
+
+ switch(pid)
+ {
+ case PID_ARP:
+ SKIP(1);
+ if (size > 0)
+ ip = get_from_arp(data, size);
+ break;
+ case PID_IP:
+ if (!mine)
+ return;
+
+ SKIP(1);
+ if (size > 0)
+ ip = get_from_ip(data, size);
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * And adjust routes/arp/ipmode if we are allowed to...
+ */
+
+ ipmode = (ctl == LAPB_I);
+
+ if (ip != 0)
+ {
+ action = update_ip_route(config, ip, ipmode, &srccall, stamp);
+
+ if (action & NEW_ROUTE)
+ if (set_route(config, ip))
+ return;
+
+ if (action & NEW_ARP)
+ if (set_arp(config, ip, &srccall))
+ return;
+
+ if (action & NEW_IPMODE)
+ if (set_ipmode(config, &srccall, ipmode))
+ return;
+ }
+}