From 17287576555a5c46fa23549e2e5f073660dccb70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Apr 1999 09:51:03 +0200 Subject: Import ax25-tools 0.0.1 from tarball --- netrom/Makefile.am | 26 +++ netrom/Makefile.in | 452 ++++++++++++++++++++++++++++++++++++++++++++++++++ netrom/netrom.4 | 51 ++++++ netrom/netromd.8 | 97 +++++++++++ netrom/netromd.c | 254 ++++++++++++++++++++++++++++ netrom/netromd.h | 41 +++++ netrom/netromr.c | 164 ++++++++++++++++++ netrom/netromt.c | 268 ++++++++++++++++++++++++++++++ netrom/nodesave.8 | 31 ++++ netrom/nodesave.c | 101 ++++++++++++ netrom/nrattach.8 | 39 +++++ netrom/nrattach.c | 240 +++++++++++++++++++++++++++ netrom/nrbroadcast | 8 + netrom/nrbroadcast.5 | 49 ++++++ netrom/nrparms.8 | 76 +++++++++ netrom/nrparms.c | 239 +++++++++++++++++++++++++++ netrom/nrports | 7 + netrom/nrports.5 | 56 +++++++ netrom/nrsdrv.8 | 44 +++++ netrom/nrsdrv.c | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 2700 insertions(+) create mode 100644 netrom/Makefile.am create mode 100644 netrom/Makefile.in create mode 100644 netrom/netrom.4 create mode 100644 netrom/netromd.8 create mode 100644 netrom/netromd.c create mode 100644 netrom/netromd.h create mode 100644 netrom/netromr.c create mode 100644 netrom/netromt.c create mode 100644 netrom/nodesave.8 create mode 100644 netrom/nodesave.c create mode 100644 netrom/nrattach.8 create mode 100644 netrom/nrattach.c create mode 100644 netrom/nrbroadcast create mode 100644 netrom/nrbroadcast.5 create mode 100644 netrom/nrparms.8 create mode 100644 netrom/nrparms.c create mode 100644 netrom/nrports create mode 100644 netrom/nrports.5 create mode 100644 netrom/nrsdrv.8 create mode 100644 netrom/nrsdrv.c (limited to 'netrom') diff --git a/netrom/Makefile.am b/netrom/Makefile.am new file mode 100644 index 0000000..03f0c0d --- /dev/null +++ b/netrom/Makefile.am @@ -0,0 +1,26 @@ + +etcfiles = nrbroadcast nrports +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 = netromd nodesave nrattach nrparms nrsdrv + +man_MANS = netrom.4 nrports.5 nrbroadcast.5 netromd.8 nodesave.8 \ + nrattach.8 nrparms.8 nrsdrv.8 + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +netromd_SOURCES = \ + netromd.c \ + netromd.h \ + netromr.c \ + netromt.c + + diff --git a/netrom/Makefile.in b/netrom/Makefile.in new file mode 100644 index 0000000..80c3c9c --- /dev/null +++ b/netrom/Makefile.in @@ -0,0 +1,452 @@ +# 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 = : +AWK = @AWK@ +CC = @CC@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +etcfiles = nrbroadcast nrports +etcdir = $(sysconfdir)/ax25 + +sbin_PROGRAMS = netromd nodesave nrattach nrparms nrsdrv + +man_MANS = netrom.4 nrports.5 nrbroadcast.5 netromd.8 nodesave.8 nrattach.8 nrparms.8 nrsdrv.8 + + +EXTRA_DIST = $(man_MANS) $(etcfiles) + +netromd_SOURCES = netromd.c netromd.h netromr.c netromt.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@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +netromd_OBJECTS = netromd.o netromr.o netromt.o +netromd_LDADD = $(LDADD) +netromd_DEPENDENCIES = +netromd_LDFLAGS = +nodesave_SOURCES = nodesave.c +nodesave_OBJECTS = nodesave.o +nodesave_LDADD = $(LDADD) +nodesave_DEPENDENCIES = +nodesave_LDFLAGS = +nrattach_SOURCES = nrattach.c +nrattach_OBJECTS = nrattach.o +nrattach_LDADD = $(LDADD) +nrattach_DEPENDENCIES = +nrattach_LDFLAGS = +nrparms_SOURCES = nrparms.c +nrparms_OBJECTS = nrparms.o +nrparms_LDADD = $(LDADD) +nrparms_DEPENDENCIES = +nrparms_LDFLAGS = +nrsdrv_SOURCES = nrsdrv.c +nrsdrv_OBJECTS = nrsdrv.o +nrsdrv_LDADD = $(LDADD) +nrsdrv_DEPENDENCIES = +nrsdrv_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man4dir = $(mandir)/man4 +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 = $(netromd_SOURCES) nodesave.c nrattach.c nrparms.c nrsdrv.c +OBJECTS = $(netromd_OBJECTS) nodesave.o nrattach.o nrparms.o nrsdrv.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps netrom/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 " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(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: + +netromd: $(netromd_OBJECTS) $(netromd_DEPENDENCIES) + @rm -f netromd + $(LINK) $(netromd_LDFLAGS) $(netromd_OBJECTS) $(netromd_LDADD) $(LIBS) + +nodesave: $(nodesave_OBJECTS) $(nodesave_DEPENDENCIES) + @rm -f nodesave + $(LINK) $(nodesave_LDFLAGS) $(nodesave_OBJECTS) $(nodesave_LDADD) $(LIBS) + +nrattach: $(nrattach_OBJECTS) $(nrattach_DEPENDENCIES) + @rm -f nrattach + $(LINK) $(nrattach_LDFLAGS) $(nrattach_OBJECTS) $(nrattach_LDADD) $(LIBS) + +nrparms: $(nrparms_OBJECTS) $(nrparms_DEPENDENCIES) + @rm -f nrparms + $(LINK) $(nrparms_LDFLAGS) $(nrparms_OBJECTS) $(nrparms_LDADD) $(LIBS) + +nrsdrv: $(nrsdrv_OBJECTS) $(nrsdrv_DEPENDENCIES) + @rm -f nrsdrv + $(LINK) $(nrsdrv_LDFLAGS) $(nrsdrv_OBJECTS) $(nrsdrv_LDADD) $(LIBS) + +install-man4: + $(mkinstalldirs) $(DESTDIR)$(man4dir) + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) 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)$(man4dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man4dir)/$$inst; \ + done + +uninstall-man4: + @list='$(man4_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.4*) 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)$(man4dir)/$$inst"; \ + rm -f $(DESTDIR)$(man4dir)/$$inst; \ + done + +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-man4 install-man5 install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man4 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 = netrom + +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 +netromd.o: netromd.c ../config.h ../pathnames.h netromd.h +netromr.o: netromr.c ../pathnames.h netromd.h +netromt.o: netromt.c ../pathnames.h netromd.h +nodesave.o: nodesave.c +nrattach.o: nrattach.c ../config.h ../pathnames.h +nrparms.o: nrparms.c ../config.h +nrsdrv.o: nrsdrv.c ../config.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)/man4 \ + $(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-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile 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 install-man4 uninstall-man4 \ +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 + + +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/netrom/netrom.4 b/netrom/netrom.4 new file mode 100644 index 0000000..67b159a --- /dev/null +++ b/netrom/netrom.4 @@ -0,0 +1,51 @@ +.TH NETROM 4 "25 July 1996" Linux "Linux Programmer's Manual" +.SH NAME +AF_NETROM \- NET/ROM amateur packet radio protocol family +.SH DESCRIPTION +.LP +.B NET/ROM +is a protocol used extensively by radio amateurs. The Linux +NET/ROM protocol family permits access to these protocols via +the standard networking +.B socket +metaphor. +.LP +The NET/ROM protocol layer only supports connected mode. IP traffic may be +stacked on top of NET/ROM frames using a non-standard extension to the +NET/ROM protocol. +.LP +The only mode of operation is connected mode which is the mode used for a +socket of type SOCK_SEQPACKET (stream sockets are not available in NET/ROM). +This requires that the user ensures output data is suitably packetised, and +that input data is read a packet at a time into a buffer of suitable size. +.LP +NET/ROM addresses consist of 6 ascii characters and a number called the +SSID. These are encoded into a sockaddr_ax25 structure which is provided to +the relevant system calls. +.LP +NET/ROM has some unusual properties. Notably in a multi-user system an AX.25 +address is often associated with a user, and some users may not have such an +association. a set of ioctl calls are provided to manage an association +table. +.LP +NET/ROM supports the following socket options for SOL_NETROM. NETROM_T1 is +the T1 timer in 1/10ths of a second, NETROM_T2 is the T2 timer in 1/10ths of +a second. NETROM_N2, the retry counter is also configurable. There is no 'infinite +retry' option supported however. It is possible for an application +to request that the NET/ROM layer return the NET/ROM header as well as the +application data, this is done via the NETROM_HDRINCL socket option. +.SH "SEE ALSO" +.BR call (1), +.BR socket (2), +.BR setsockopt(2), +.BR getsockopt(2), +.BR nrbroadcast (5), +.BR nrports (5), +.BR netromd (8), +.BR noderest (8), +.BR nodesave (8), +.BR nrctl (8), +.BR nrparms (8). +.LP +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/netrom/netromd.8 b/netrom/netromd.8 new file mode 100644 index 0000000..ef1860e --- /dev/null +++ b/netrom/netromd.8 @@ -0,0 +1,97 @@ +.TH NETROMD 8 "20 August 1996" Linux "Linux System Managers Manual" +.SH NAME +netromd \- Send and receive NET/ROM routing messages +.SH SYNOPSIS +.B netromd [-c] [-d] [-i] [-l] [-p pause] [-q quality] [-t interval] [-v] +.SH DESCRIPTION +.LP +For a NET/ROM based network to operate correctly, a periodic broadcast of +routing information needs to occur. Typically this occurs once every hour on +every port which is expected to carry NET/ROM traffic. The purpose of +.B netromd +is to send and receive NET/ROM routing broadcasts. To operate correctly a +set of parameters that corresponds to each AX.25 port needs to be passed to +the program. This information is encoded in a configuration file, by default +which is /etc/ax25/nrbroadcast with each line representing one +port, see the manual page for +.BR nrbroadcast (5). +.LP +To cut down the length of these routing broadcasts, only the information +about the highest quality neighbour for a particular node is transmitted. +The transmission is also limited to those node that have a certain minimum +value in their obsolesence count, this value is decremented every time a +routing broadcast is transmitted, and is refreshed by receiving a routing +broadcast which contains that particular node. +.LP +The value of the default quality is traditionally assigned a value that +represents the quality of the radio links on that port. A higher number +representing better radio links with 255 (the maximum) reserved for wire +connections. The practise in the UK is to set the default quality to a low +value, typically 10, and manually set up the trusted neighbouring nodes in +the neighbour list manually. The worst quality for auto-updates value is a +way to filter out low quality (ie distant) nodes. +.LP +The verbose flag may be either 0 or 1, representing no and yes. By +specifying no, the program will only generate a routing message containing +information about the node on which it is running, by specifying the yes +option, all the information in the nodes routing tables will be transmitted. +The quality advertised for the other node callsigns on this machine may be +set using the \-q option. +.LP +Between each transmission +.B netromd +pauses for five seconds (default) in order to avoid flooding the channels +that it must broadcast on. The value of this delay is settable with the \-p +option. +.SH OPTIONS +.TP 16 +.BI \-c +Forces strict compliance to Software 2000 specifications. At present this +only determines how node mnemonics with lower case characters will be handled. +With compliance enabled mixed case node mnemonics will be ignored. The default +is to accept node mnemonics of mixed case. +.TP 16 +.BI \-d +Switches on debugging messages, the default is off. Logging must be enabled +for them to be output. +.TP 16 +.BI \-i +Transmit a routing broadcast immediately, the default is to wait for the +time interval to elapse before transmitting the first routing broadcast. +.TP 16 +.BI \-l +Enables logging of errors and debug messages to the system log. The default +is off. +.TP 16 +.BI "\-p pause" +Sets the delay between transmissions of individual routing broadcast +packets. The default is five seconds. +.TP 16 +.BI "\-q quality" +Sets the quality of the subsidiary nodes relative to the main node. The +default is 255. +.TP 16 +.BI "\-t interval" +The time interval between routing broadcasts, in minutes. The default is 60 +minutes. +.TP 16 +.BI \-v +Display the version. +.SH FILES +.nf +/proc/net/nr_neigh +.br +/proc/net/nr_nodes +.br +/etc/ax25/axports +.br +/etc/ax25/nrbroadcast +.fi +.SH "SEE ALSO" +.BR ax25 (4), +.BR axports (5), +.BR nrbroadcast (5), +.BR netrom (4), +.BR nrparms (8). +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/netrom/netromd.c b/netrom/netromd.c new file mode 100644 index 0000000..fa80c9b --- /dev/null +++ b/netrom/netromd.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "../pathnames.h" +#include "netromd.h" + +struct port_struct port_list[20]; + +int port_count = FALSE; +int compliant = FALSE; +int debug = FALSE; +int logging = FALSE; + +ax25_address my_call; +ax25_address node_call; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static int bcast_config_load_ports(void) +{ + char buffer[255], port[32], *s; + FILE *fp; + + if ((fp = fopen(CONF_NETROMD_FILE, "r")) == NULL) { + fprintf(stderr, "netromd: cannot open config file\n"); + return -1; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) == 0 || buffer[0] == '#') + continue; + + if (sscanf(buffer, "%s %d %d %d %d", + port, + &port_list[port_count].minimum_obs, + &port_list[port_count].default_qual, + &port_list[port_count].worst_qual, + &port_list[port_count].verbose) == -1) { + fprintf(stderr, "netromd: unable to parse: %s", buffer); + return -1; + } + + if (ax25_config_get_addr(port) == NULL) { + fprintf(stderr, "netromd: invalid port name - %s\n", port); + return -1; + } + + port_list[port_count].port = strdup(port); + port_list[port_count].device = strdup(ax25_config_get_dev(port_list[port_count].port)); + + if (port_list[port_count].minimum_obs < 0 || port_list[port_count].minimum_obs > 6) { + fprintf(stderr, "netromd: invalid minimum obsolescence\n"); + return -1; + } + + if (port_list[port_count].default_qual < 0 || port_list[port_count].default_qual > 255) { + fprintf(stderr, "netromd: invalid default quality\n"); + return -1; + } + + if (port_list[port_count].worst_qual < 0 || port_list[port_count].worst_qual > 255) { + fprintf(stderr, "netromd: invalid worst quality\n"); + return -1; + } + + if (port_list[port_count].verbose != 0 && port_list[port_count].verbose != 1) { + fprintf(stderr, "netromd: invalid verbose setting\n"); + return -1; + } + + port_count++; + } + + fclose(fp); + + if (port_count == 0) + return -1; + + return 0; +} + +int main(int argc, char **argv) +{ + unsigned char buffer[512]; + int size, s, i; + struct sockaddr sa; + int asize; + struct timeval timeout; + time_t timenow, timelast; + int interval = 3600; + int localval = 255; + int pause = 5; + fd_set fdset; + + time(&timelast); + + while ((i = getopt(argc, argv, "cdilp:q:t:v")) != -1) { + switch (i) { + case 'c': + compliant = TRUE; + break; + case 'd': + debug = TRUE; + break; + case 'i': + timelast = 0; + break; + case 'l': + logging = TRUE; + break; + case 'p': + pause = atoi(optarg); + if (pause < 1 || pause > 120) { + fprintf(stderr, "netromd: invalid pause value\n"); + return 1; + } + break; + case 'q': + localval = atoi(optarg); + if (localval < 10 || localval > 255) { + fprintf(stderr, "netromd: invalid local quality\n"); + return 1; + } + break; + case 't': + interval = atoi(optarg) * 60; + if (interval < 60 || interval > 7200) { + fprintf(stderr, "netromd: invalid time interval\n"); + return 1; + } + break; + case 'v': + printf("netromd: %s\n", VERSION); + return 0; + case '?': + case ':': + fprintf(stderr, "usage: netromd [-d] [-i] [-l] [-q quality] [-t interval] [-v]\n"); + return 1; + } + } + + signal(SIGTERM, terminate); + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "netromd: no AX.25 ports defined\n"); + return 1; + } + + if (nr_config_load_ports() == 0) { + fprintf(stderr, "netromd: no NET/ROM ports defined\n"); + return 1; + } + + if (bcast_config_load_ports() == -1) { + fprintf(stderr, "netromd: no NET/ROM broadcast ports defined\n"); + return 1; + } + + ax25_aton_entry(nr_config_get_addr(NULL), (char *)&my_call); + ax25_aton_entry("NODES", (char *)&node_call); + + if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { + perror("netromd: socket"); + return 1; + } + + if (!daemon_start(TRUE)) { + fprintf(stderr, "netromd: cannot become a daemon\n"); + return 1; + } + + if (logging) { + openlog("netromd", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + for (;;) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if (select(s + 1, &fdset, NULL, NULL, &timeout) == -1) + continue; /* Signal received ? */ + + if (FD_ISSET(s, &fdset)) { + asize = sizeof(sa); + + if ((size = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &asize)) == -1) { + if (logging) { + syslog(LOG_ERR, "recvfrom: %m"); + closelog(); + } + return 1; + } + + if (ax25_cmp((ax25_address *)(buffer + 1), &node_call) == 0 && + ax25_cmp((ax25_address *)(buffer + 8), &my_call) != 0 && + buffer[16] == NETROM_PID && buffer[17] == NODES_SIG) { + for (i = 0; i < port_count; i++) { + if (strcmp(port_list[i].device, sa.sa_data) == 0) { + if (debug && logging) + syslog(LOG_DEBUG, "receiving NODES broadcast on port %s from %s\n", port_list[i].port, ax25_ntoa((ax25_address *)(buffer + 8))); + receive_nodes(buffer + 18, size - 18, (ax25_address *)(buffer + 8), i); + break; + } + } + } + } + + time(&timenow); + + if ((timenow - timelast) > interval) { + timelast = timenow; + transmit_nodes(localval, pause); + } + } +} diff --git a/netrom/netromd.h b/netrom/netromd.h new file mode 100644 index 0000000..3007b02 --- /dev/null +++ b/netrom/netromd.h @@ -0,0 +1,41 @@ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define NETROM_PID 0xCF + +#define NODES_SIG 0xFF + +#define CALLSIGN_LEN 7 +#define MNEMONIC_LEN 6 +#define QUALITY_LEN 1 + +#define NODES_PACLEN 256 +#define ROUTE_LEN (CALLSIGN_LEN+MNEMONIC_LEN+CALLSIGN_LEN+QUALITY_LEN) + +struct port_struct { + char *device; + char *port; + int minimum_obs; + int default_qual; + int worst_qual; + int verbose; +}; + +extern struct port_struct port_list[]; + +extern int port_count; +extern int debug; +extern int logging; + +extern ax25_address my_call; +extern ax25_address node_call; + +/* In netromt.c */ +extern void transmit_nodes(int, int); + +/* In netromr.c */ +extern void receive_nodes(unsigned char *, int, ax25_address *, int); diff --git a/netrom/netromr.c b/netrom/netromr.c new file mode 100644 index 0000000..eafd225 --- /dev/null +++ b/netrom/netromr.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "../pathnames.h" + +#include "netromd.h" + +extern int compliant; + +static int validmnemonic(char *mnemonic) +{ + if (compliant) { + if (strspn(mnemonic, "#_&-/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") == strlen(mnemonic)) + return TRUE; + } else { + if (strspn(mnemonic, "#_&-/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") == strlen(mnemonic)) + return TRUE; + } + + return FALSE; +} + +void receive_nodes(unsigned char *buffer, int length, ax25_address *neighbour, int index) +{ + struct nr_route_struct nr_node; + char neigh_buffer[90], *portcall, *p; + FILE *fp; + int s; + int quality, obs_count, qual, lock; + char *addr, *callsign, *device; + + nr_node.type = NETROM_NODE; + /*nr_node.ndigis = 0;*/ + + sprintf(neigh_buffer, "%s/obsolescence_count_initialiser", PROC_NR_SYSCTL_DIR); + + if ((fp = fopen(neigh_buffer, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromr: cannot open %s\n", neigh_buffer); + return; + } + + fgets(neigh_buffer, 90, fp); + + obs_count = atoi(neigh_buffer); + + fclose(fp); + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + if (logging) + syslog(LOG_ERR, "netromr: socket: %m"); + return; + } + + if ((fp = fopen(PROC_NR_NEIGH_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromr: cannot open %s\n", PROC_NR_NEIGH_FILE); + close(s); + return; + } + + fgets(neigh_buffer, 90, fp); + + portcall = ax25_ntoa(neighbour); + + quality = port_list[index].default_qual; + + while (fgets(neigh_buffer, 90, fp) != NULL) { + addr = strtok(neigh_buffer, " "); + callsign = strtok(NULL, " "); + device = strtok(NULL, " "); + qual = atoi(strtok(NULL, " ")); + lock = atoi(strtok(NULL, " ")); + + if (strcmp(callsign, portcall) == 0 && + strcmp(device, port_list[index].device) == 0 && + lock == 1) { + quality = qual; + break; + } + } + + fclose(fp); + + nr_node.callsign = *neighbour; + memcpy(nr_node.mnemonic, buffer, MNEMONIC_LEN); + nr_node.mnemonic[MNEMONIC_LEN] = '\0'; + + if ((p = strchr(nr_node.mnemonic, ' ')) != NULL) + *p = '\0'; + + if (!validmnemonic(nr_node.mnemonic)) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route, invalid mnemonic - %s\n", nr_node.mnemonic); + } else { + nr_node.neighbour = *neighbour; + strcpy(nr_node.device, port_list[index].device); + nr_node.quality = quality; + nr_node.obs_count = obs_count; + + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + if (logging) + syslog(LOG_ERR, "netromr: SIOCADDRT: %m"); + close(s); + return; + } + } + + buffer += MNEMONIC_LEN; + length -= MNEMONIC_LEN; + + while (length >= ROUTE_LEN) { + /* + * Ensure that a) the route is not via me, and + * b) it is better than my minimum acceptable quality + */ + if (ax25_cmp(&my_call, (ax25_address *)(buffer + 13)) != 0 && + buffer[20] > port_list[index].worst_qual) { + memcpy(&nr_node.callsign, buffer + 0, CALLSIGN_LEN); + memcpy(nr_node.mnemonic, buffer + 7, MNEMONIC_LEN); + nr_node.mnemonic[MNEMONIC_LEN] = '\0'; + + if ((p = strchr(nr_node.mnemonic, ' ')) != NULL) + *p = '\0'; + + if (!validmnemonic(nr_node.mnemonic)) { + if (debug && logging) + syslog(LOG_DEBUG, "rejecting route, invalid mnemonic - %s\n", nr_node.mnemonic); + } else { + nr_node.neighbour = *neighbour; + strcpy(nr_node.device, port_list[index].device); + nr_node.quality = ((quality * buffer[20]) + 128) / 256; + nr_node.obs_count = obs_count; + + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + if (logging) + syslog(LOG_ERR, "netromr: SIOCADDRT: %m"); + close(s); + return; + } + } + } + + buffer += ROUTE_LEN; + length -= ROUTE_LEN; + } + + close(s); +} diff --git a/netrom/netromt.c b/netrom/netromt.c new file mode 100644 index 0000000..d22caf1 --- /dev/null +++ b/netrom/netromt.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../pathnames.h" +#include "netromd.h" + +static int build_header(unsigned char *message) +{ + message[0] = NODES_SIG; + + strcpy(message + 1, nr_config_get_alias(NULL)); + strncat(message + 1, " ", MNEMONIC_LEN - strlen(message + 1)); + + return 7; +} + +static void build_mine(int s, struct full_sockaddr_ax25 *dest, int dlen, int localval, int pause) +{ + unsigned char message[100]; + char buffer[255], *port, *p; + FILE *fp; + int len; + + len = build_header(message); + + if ((fp = fopen(CONF_NRPORTS_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open nrports file\n"); + return; + } + + while (fgets(buffer, 255, fp) != NULL) { + if ((p = strchr(buffer, '\n')) != NULL) + *p = '\0'; + + if (strlen(buffer) == 0 || buffer[0] == '#') + continue; + + port = strtok(buffer, " \t"); + + if (nr_config_get_addr(port) == NULL) + continue; + + if (strcmp(nr_config_get_addr(port), nr_config_get_addr(NULL)) == 0) + continue; + + if (ax25_aton_entry(nr_config_get_addr(port), message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign in nrports\n"); + fclose(fp); + return; + } + len += CALLSIGN_LEN; + + strcpy(message + len, nr_config_get_alias(port)); + strncat(message + len, " ", MNEMONIC_LEN - strlen(message + len)); + len += MNEMONIC_LEN; + + ax25_aton_entry(nr_config_get_addr(NULL), message + len); + len += CALLSIGN_LEN; + + message[len] = localval; + len += QUALITY_LEN; + } + + fclose(fp); + + if (sendto(s, message, len, 0, (struct sockaddr *)dest, dlen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: sendto: %m"); + } + + sleep(pause); +} + +static void build_others(int s, int min_obs, struct full_sockaddr_ax25 *dest, int dlen, int port, int pause) +{ + unsigned char message[300]; + FILE *fpnodes, *fpneigh; + char nodes_buffer[90]; + char neigh_buffer[90]; + char *callsign, *mnemonic, *neighbour; + int which, number, quality, neigh_no, obs_count; + int olen, len; + + if ((fpnodes = fopen(PROC_NR_NODES_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open %s\n", PROC_NR_NODES_FILE); + return; + } + + if ((fpneigh = fopen(PROC_NR_NEIGH_FILE, "r")) == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: cannot open %s\n", PROC_NR_NEIGH_FILE); + fclose(fpnodes); + return; + } + + fgets(nodes_buffer, 90, fpnodes); + + do { + len = olen = build_header(message); + + while (fgets(nodes_buffer, 90, fpnodes) != NULL) { + callsign = strtok(nodes_buffer, " "); + mnemonic = strtok(NULL, " "); + which = atoi(strtok(NULL, " ")); + number = atoi(strtok(NULL, " ")); + quality = atoi(strtok(NULL, " ")); + obs_count = atoi(strtok(NULL, " ")); + neigh_no = atoi(strtok(NULL, " ")); + neighbour = NULL; + + if (obs_count < min_obs || quality == 0) continue; + + /* "Blank" mnemonic */ + if (strcmp(mnemonic, "*") == 0) + mnemonic = ""; + + fseek(fpneigh, 0L, SEEK_SET); + + fgets(neigh_buffer, 90, fpneigh); + + while (fgets(neigh_buffer, 90, fpneigh) != NULL) { + if (atoi(strtok(neigh_buffer, " ")) == neigh_no) { + neighbour = strtok(NULL, " "); + break; + } + } + + if (neighbour == NULL) { + if (logging) + syslog(LOG_ERR, "netromt: corruption in nodes/neighbour matching\n"); + continue; + } + + if (ax25_aton_entry(callsign, message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign '%s' in /proc/net/nr_nodes\n", callsign); + continue; + } + len += CALLSIGN_LEN; + + strcpy(message + len, mnemonic); + strncat(message + len, " ", MNEMONIC_LEN - strlen(message + len)); + len += MNEMONIC_LEN; + + if (ax25_aton_entry(neighbour, message + len) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: invalid callsign '%s' in /proc/net/nr_neigh\n", neighbour); + len -= (CALLSIGN_LEN + MNEMONIC_LEN); + continue; + } + len += CALLSIGN_LEN; + + message[len] = quality; + len += QUALITY_LEN; + + /* No room for another entry? */ + if (len + ROUTE_LEN > NODES_PACLEN) + break; + } + + /* Only send it if there is more that just the header */ + if (len > olen) { + if (sendto(s, message, len, 0, (struct sockaddr *)dest, dlen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: sendto: %m"); + } + + sleep(pause); + } + + /* If the packet was not full then we are done */ + } while (len + ROUTE_LEN > NODES_PACLEN); + + fclose(fpnodes); + fclose(fpneigh); +} + +void transmit_nodes(int localval, int pause) +{ + struct full_sockaddr_ax25 dest; + struct full_sockaddr_ax25 src; + int s, dlen, slen; + char path[25], *addr; + int i; + + switch (fork()) { + case 0: + break; + case -1: + if (logging) + syslog(LOG_ERR, "netromt: fork: %m\n"); + return; + default: + return; + } + + dlen = ax25_aton("NODES", &dest); + + for (i = 0; i < port_count; i++) { + + addr = ax25_config_get_addr(port_list[i].port); + + if (addr == NULL) continue; + + if (debug && logging) + syslog(LOG_DEBUG, "transmitting NODES broadcast on port %s\n", port_list[i].port); + + sprintf(path, "%s %s", nr_config_get_addr(NULL), addr); + + ax25_aton(path, &src); + slen = sizeof(struct full_sockaddr_ax25); + + if ((s = socket(AF_AX25, SOCK_DGRAM, NETROM_PID)) < 0) { + if (logging) + syslog(LOG_ERR, "netromt: socket: %m"); + continue; + } + + if (bind(s, (struct sockaddr *)&src, slen) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: bind: %m"); + close(s); + continue; + } + + build_mine(s, &dest, dlen, localval, pause); + + if (port_list[i].verbose) + build_others(s, port_list[i].minimum_obs, &dest, dlen, i, pause); + + close(s); + } + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + if (logging) + syslog(LOG_ERR, "netromt: socket: %m"); + exit(1); + } + + if (ioctl(s, SIOCNRDECOBS, &i) == -1) { + if (logging) + syslog(LOG_ERR, "netromt: SIOCNRDECOBS: %m"); + exit(1); + } + + close(s); + + exit(0); +} diff --git a/netrom/nodesave.8 b/netrom/nodesave.8 new file mode 100644 index 0000000..626778b --- /dev/null +++ b/netrom/nodesave.8 @@ -0,0 +1,31 @@ +.TH NODESAVE 8 "21 May 1996" Linux "Linux System Managers Manual" +.SH NAME +nodesave \- Saves NET/ROM routing information +.SH SYNOPSIS +.B nodesave [filename] +.SH DESCRIPTION +.LP +.B Nodesave +saves the contents of the /proc filesystem entries for the NET/ROM routing +tables. The output of the program is in the form of a Bourne shell script +that calls nrparms(8) to recreate the NET/ROM routing information. If no +filename is given on the command line, the program writes the script to +stdout. +.LP +Typically +.B nodesave +would be used when taking a system off-air so that the NET/ROM routing may +be quickly restored when the system is brought back on-line. +.SH FILES +.nf +/proc/net/nr_neigh +.br +/proc/net/nr_nodes +.fi +.SH "SEE ALSO" +.BR netrom (4), +.BR netromd (8), +.BR nrparms (8). +.LP +.SH AUTHOR +Tomi Manninen OH2BNS diff --git a/netrom/nodesave.c b/netrom/nodesave.c new file mode 100644 index 0000000..3eab61b --- /dev/null +++ b/netrom/nodesave.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +int main(int argc, char **argv) +{ + FILE *fp = stdout; + struct proc_nr_nodes *nodes, *nop; + struct proc_nr_neigh *neighs, *nep; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nodesave: no AX.25 port data configured\n"); + return 1; + } + + if (argc > 1) { + if ((fp = fopen(argv[1], "w")) == NULL) { + fprintf(stderr, "nodesave: cannot open file %s\n", argv[1]); + return 1; + } + } + + if ((neighs = read_proc_nr_neigh()) == NULL && errno != 0) { + perror("nodesave: read_proc_nr_neigh"); + fclose(fp); + return 1; + } + + if ((nodes = read_proc_nr_nodes()) == NULL && errno != 0) { + perror("nodesave: read_proc_nr_nodes"); + free_proc_nr_neigh(neighs); + fclose(fp); + return 1; + } + + fprintf(fp, "#! /bin/sh\n#\n# Locked routes:\n#\n"); + + for (nep = neighs; nep != NULL; nep = nep->next) { + if (nep->lock) { + fprintf(fp, "nrparms -routes \"%s\" %s + %d\n", + ax25_config_get_name(nep->dev), + nep->call, + nep->qual); + } + } + + fprintf(fp, "#\n# Nodes:\n#\n"); + + for (nop = nodes; nop != NULL; nop = nop->next) { + if ((nep = find_neigh(nop->addr1, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual1, + nop->obs1, + ax25_config_get_name(nep->dev), + nep->call); + } + + if (nop->n > 1 && (nep = find_neigh(nop->addr2, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual2, + nop->obs2, + ax25_config_get_name(nep->dev), + nep->call); + } + + if (nop->n > 2 && (nep = find_neigh(nop->addr3, neighs)) != NULL) { + fprintf(fp, "nrparms -nodes %s + \"%s\" %d %d \"%s\" %s\n", + nop->call, + nop->alias, + nop->qual3, + nop->obs3, + ax25_config_get_name(nep->dev), + nep->call); + } + } + + free_proc_nr_neigh(neighs); + free_proc_nr_nodes(nodes); + + fclose(fp); + + if (argc > 1) { + chmod(argv[1], S_IEXEC); + } + + return 0; +} diff --git a/netrom/nrattach.8 b/netrom/nrattach.8 new file mode 100644 index 0000000..692e3f2 --- /dev/null +++ b/netrom/nrattach.8 @@ -0,0 +1,39 @@ +.TH NRATTACH 8 "21 May 1996" Linux "Linux System Managers Manual" +.SH NAME +nrattach \- Start a NET/ROM interface +.SH SYNOPSIS +.B nrattach [-i inetaddr] [-m mtu] [-v] port +.SH DESCRIPTION +.LP +.B Nrattach +takes many of the parameters for the port from the nrports(5) file. The +paclen parameter is used for the device mtu unless overridden by a value on +the command line. The port argument is the name of a port as given in the +nrports(5) file. +.LP +.B Nrattach +tries to find the first free NET/ROM device in the system. The devices +checked are nr0, nr1, nr2 and nr3 in that order. If no free NET/ROM device +is available an error is generated and the program terminates. +.SH OPTIONS +.TP 16 +.BI "\-i inetaddr" +Set the internet address of the interface. This address may either be a +dotted decimal address or a host name. +.TP 16 +.BI "\-m mtu" +Sets the mtu of the interface. If this value is not given then the value is +taken from the paclen parameter in nrports. +.TP 16 +.BI \-v +Display the version. +.SH "SEE ALSO" +.BR netrom (4), +.BR nrparms (4), +.BR nrports (5), +.BR ifconfig (8). +.SH BUGS +The program can be run many times with the same arguments creating many +instances of the same attributes on different devices. Not a good idea. +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/netrom/nrattach.c b/netrom/nrattach.c new file mode 100644 index 0000000..aee0936 --- /dev/null +++ b/netrom/nrattach.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "../pathnames.h" + +char *callsign; +int mtu = 0; + +int readconfig(char *port) +{ + FILE *fp; + char buffer[90], *s; + int n = 0; + + if ((fp = fopen(CONF_NRPORTS_FILE, "r")) == NULL) { + fprintf(stderr, "nrattach: cannot open nrports file\n"); + return FALSE; + } + + while (fgets(buffer, 90, fp) != NULL) { + n++; + + if ((s = strchr(buffer, '\n')) != NULL) + *s = '\0'; + + if (strlen(buffer) > 0 && *buffer == '#') + continue; + + if ((s = strtok(buffer, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if (strcmp(s, port) != 0) + continue; + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + callsign = strdup(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "nrattach: unable to parse line %d of the nrports file\n", n); + return FALSE; + } + + if (mtu == 0) { + if ((mtu = atoi(s)) <= 0) { + fprintf(stderr, "nrattach: invalid paclen setting\n"); + return FALSE; + } + } + + fclose(fp); + + return TRUE; + } + + fclose(fp); + + fprintf(stderr, "nrattach: cannot find port %s in nrports\n", port); + + return FALSE; +} + +int getfreedev(char *dev) +{ + struct ifreq ifr; + int fd; + int i; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("nrattach: socket"); + return FALSE; + } + + for (i = 0; i < 4; i++) { + sprintf(dev, "nr%d", i); + strcpy(ifr.ifr_name, dev); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCGIFFLAGS"); + return FALSE; + } + + if (!(ifr.ifr_flags & IFF_UP)) { + close(fd); + return TRUE; + } + } + + close(fd); + + return FALSE; +} + +int startiface(char *dev, struct hostent *hp) +{ + struct ifreq ifr; + char call[7]; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("nrattach: socket"); + return FALSE; + } + + strcpy(ifr.ifr_name, dev); + + if (hp != NULL) { + ifr.ifr_addr.sa_family = AF_INET; + + ifr.ifr_addr.sa_data[0] = 0; + ifr.ifr_addr.sa_data[1] = 0; + ifr.ifr_addr.sa_data[2] = hp->h_addr_list[0][0]; + ifr.ifr_addr.sa_data[3] = hp->h_addr_list[0][1]; + ifr.ifr_addr.sa_data[4] = hp->h_addr_list[0][2]; + ifr.ifr_addr.sa_data[5] = hp->h_addr_list[0][3]; + ifr.ifr_addr.sa_data[6] = 0; + + if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { + perror("nrattach: SIOCSIFADDR"); + return FALSE; + } + } + + if (ax25_aton_entry(callsign, call) == -1) + return FALSE; + + ifr.ifr_hwaddr.sa_family = ARPHRD_NETROM; + memcpy(ifr.ifr_hwaddr.sa_data, call, 7); + + if (ioctl(fd, SIOCSIFHWADDR, &ifr) != 0) { + perror("nrattach: SIOCSIFHWADDR"); + return FALSE; + } + + ifr.ifr_mtu = mtu; + + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("nrattach: SIOCSIFMTU"); + return FALSE; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCGIFFLAGS"); + return FALSE; + } + + ifr.ifr_flags &= IFF_NOARP; + ifr.ifr_flags |= IFF_UP; + ifr.ifr_flags |= IFF_RUNNING; + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { + perror("nrattach: SIOCSIFFLAGS"); + return FALSE; + } + + close(fd); + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + int fd; + char dev[64]; + struct hostent *hp = NULL; + + while ((fd = getopt(argc, argv, "i:m:v")) != -1) { + switch (fd) { + case 'i': + if ((hp = gethostbyname(optarg)) == NULL) { + fprintf(stderr, "nrattach: invalid internet name/address - %s\n", optarg); + return 1; + } + break; + case 'm': + if ((mtu = atoi(optarg)) <= 0) { + fprintf(stderr, "nrattach: invalid mtu size - %s\n", optarg); + return 1; + } + break; + case 'v': + printf("nrattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: nrattach [-i inetaddr] [-m mtu] [-v] port\n"); + return 1; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "usage: nrattach [-i inetaddr] [-m mtu] [-v] port\n"); + return 1; + } + + if (!readconfig(argv[optind])) + return 1; + + if (!getfreedev(dev)) { + fprintf(stderr, "nrattach: cannot find free NET/ROM device\n"); + return 1; + } + + if (!startiface(dev, hp)) + return 1; + + printf("NET/ROM port %s bound to device %s\n", argv[optind], dev); + + return 0; +} diff --git a/netrom/nrbroadcast b/netrom/nrbroadcast new file mode 100644 index 0000000..8584b22 --- /dev/null +++ b/netrom/nrbroadcast @@ -0,0 +1,8 @@ +# /etc/ax25/nrbroadcast +# +# The format of this file is: +# +# ax25_name min_obs def_qual worst_qual verbose +# +1 5 192 100 0 +2 5 255 100 1 diff --git a/netrom/nrbroadcast.5 b/netrom/nrbroadcast.5 new file mode 100644 index 0000000..7258bc7 --- /dev/null +++ b/netrom/nrbroadcast.5 @@ -0,0 +1,49 @@ +.TH NRBROADCAST 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +nrbroadcast \- NET/ROM routing broadcast configuration file. +.SH DESCRIPTION +.LP +.B Nrbroadcast +is an ASCII file that contains information about each of the physical AX.25 +ports that are to have NET/ROM routing broadcasts transmitted from them. +.LP +Each line has the following format, each field being delimited by white space: +.sp +.RS +port minobs defqual worstqual verbose +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B port +the port name of the AX.25 port to broadcast on. +.TP +.B minobs +this is the minimum obsolescence count of a routing table entry to be +broadcast on this port. +.TP +.B defqual +this is the default quality of an incoming routing broadcast from an unknown +neighbour. +.TP +.B worstqual +this is the worst quality node received from a routing broadcast that will +be added to our routing table. +.TP +.B verbose +whether the routes to all of my nodes in my routing table, or just the nodes +resident on my machine are to be broadcast. +.RE +.SH FILES +.LP +/etc/ax25/nrbroadcast +.br +/etc/ax25/axports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR axports (5), +.BR netromd (8), +.BR nrparms (8). diff --git a/netrom/nrparms.8 b/netrom/nrparms.8 new file mode 100644 index 0000000..38d3dd8 --- /dev/null +++ b/netrom/nrparms.8 @@ -0,0 +1,76 @@ +.TH NRPARMS 8 "25 January 1997" Linux "Linux System Managers Manual" +.SH NAME +nrparms \- Configure the NET/ROM interface. +.SH SYNOPSIS +.B nrparms -nodes node +|- ident quality count port neighbour [digicall...] +.LP +.B nrparms -routes port nodecall [digicall...] +|- quality +.LP +.B nrparms -version +.SH DESCRIPTION +.LP +This program is used to manipulate the routing tables of the NET/ROM network +layer, or to get and set many of the network and transport layer parameters +for the NET/ROM protocol. The program has three basic modes of operation, +node setting, neighbour setting and general parameter setting. The syntax +for the node and neighbour setting is taken from the original NET/ROM manual +and is therefore not very UNIXy but should be familiar to those familiar +with NET/ROMs or TheNet. +.LP +To set up a new route to a NET/ROM node in the routing tables you must use +the nodes option. All of the parameters are needed to add the node. It is +probably best to illustrate with an example: +.LP +.B nrparms -nodes GB7BPQ + NMCLUS 120 6 vhf G8ROU-3 +.LP +This creates a new route to a distant node with the callsign GB7BPQ and the +alias NMCLUS, it has a quality of 120 (out of 255) and has an obsolescence +count of six and packets for that node should be sent on the AX.25 port named +vhf to my immediate neighbour G8ROU-3. The callsigns of the node and the +neighbour may be the same. For example to set up the node G8ROU-3 which is +also my immediate neighbour, I would use: +.LP +.B nrparms -nodes G8ROU-3 + MATLCK 200 6 vhf G8ROU-3 +.LP +If the ident of the remote node is not known, it is possible to add a +node with a blank ident. To do this an ident of '*' must be entered on +the command line. Because of the command line expansion that shells do, the * +must be escaped by enclosing it in quotes. +.LP +It is also possible to remove a route to a distant node with the same +command except that the + is replaced by a -. The other parameters must also +be present. If the node has not other routes then the node will be deleted, +and the neighbour node that the connections go via may also be deleted if no +other node route uses it, and it is not a locked neighbour entry. +.LP +When setting up a new node, a new neighbour entry may also be created. This +will have a default value. For that neighbour to be meaningful in the +automatic routing process, it must have a more reasonable entry in the +neighbours list. To do this the routes option of the command must be used. +An example: +.LP +.B nrparms -routes ax0 G8ROU-3 + 120 +.LP +This will create (or update) the neighbour entry for G8ROU-3 with a quality +of 120 and it will be locked, it will not create a node entry for the +neighbour. This quality will be used by the +.BR netromd (8) +program when calculating route qualities via this neighbour. Normally once a +neighbour has zero node routes going via it, it will be deleted. Locking a +neighbour prevents the deletion from occurring. To unlock a neighbour entry, +the same command is used but with the + replaced by a -. +.SH FILES +.LP +/etc/ax25/axports +.br +/etc/ax25/nrports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR nrports (5), +.BR axparms (8), +.BR netromd (8), +.BR nrctl (8), +.BR nrparms (8). +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/netrom/nrparms.c b/netrom/nrparms.c new file mode 100644 index 0000000..7e89ff9 --- /dev/null +++ b/netrom/nrparms.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +char nodes_usage[] = "usage: nrparms -nodes nodecall +|- ident quality count port neighbour [digicall...]\n"; +char routes_usage[] = "usage: nrparms -routes port nodecall [digicall...] +|- pathquality\n"; + +void nodes(int s, char *nodecall, char *op, char *ident, int quality, int count, char *port, char *neighbour, char *digis[]) +{ + struct nr_route_struct nr_node; + char *p, *q, *dev; + int i; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nrparms: nodes: no AX.25 ports configured\n"); + exit(1); + } + + nr_node.type = NETROM_NODE; + /*nr_node.ndigis = 0;*/ + + if (op[0] != '+' && op[0] != '-') { + fprintf(stderr, "nrparms: nodes: invalid operation %s\n", op); + close(s); + exit(1); + } + + if (quality < 1 || quality > 255) { + fprintf(stderr, "nrparms: nodes: invalid quality %d\n", quality); + close(s); + exit(1); + } + + if (count < 1 || count > 6) { + fprintf(stderr, "nrparms: nodes: invalid obs count %d\n", count); + close(s); + exit(1); + } + + if (ax25_aton_entry(nodecall, nr_node.callsign.ax25_call) != 0) { + fprintf(stderr, "nrparms: nodes: invalid callsign %s\n", nodecall); + close(s); + exit(1); + } + + if (strlen(ident) > 7) { + fprintf(stderr, "nrparms: nodes: invalid length of mnemonic %s\n", ident); + close(s); + exit(1); + } + + if (strcmp(ident, "*") != 0) { + for (p = ident, q = nr_node.mnemonic; *p != '\0'; p++, q++) + *q = toupper(*p); + *q = '\0'; + + if (strspn(nr_node.mnemonic, "&#-_/ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") != strlen(nr_node.mnemonic)) { + fprintf(stderr, "nrparms: nodes: invalid ident %s\n", ident); + close(s); + exit(1); + } + } else { + strcpy(nr_node.mnemonic, ""); + } + + if (ax25_aton_entry(neighbour, nr_node.neighbour.ax25_call) != 0) { + fprintf(stderr, "nrparms: nodes: invalid callsign %s\n", neighbour); + close(s); + exit(1); + } + /* + for (i = 0; i < AX25_MAX_DIGIS && digis[i] != NULL; i++) { + if (ax25_aton_entry(digis[i], nr_node.digipeaters[i].ax25_call) != 0) { + fprintf(stderr, "nrparms: invalid callsign %s\n", digis[i]); + close(s); + exit(1); + } + nr_node.ndigis++; + } */ + + if ((dev = ax25_config_get_dev(port)) == NULL) { + fprintf(stderr, "nrparms: nodes: invalid port name - %s\n", port); + close(s); + exit(1); + } + + strcpy(nr_node.device, dev); + + nr_node.quality = quality; + nr_node.obs_count = count; + + if (op[0] == '+') { + if (ioctl(s, SIOCADDRT, &nr_node) == -1) { + perror("nrparms: SIOCADDRT"); + close(s); + exit(1); + } + } else { + if (ioctl(s, SIOCDELRT, &nr_node) == -1) { + perror("nrparms: SIOCDELRT"); + close(s); + exit(1); + } + } +} + +void routes(int s, char *port, char *nodecall, char *rest[]) +{ + struct nr_route_struct nr_neigh; + char *dev, *op; + int i, quality; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "nrparms: routes: no AX.25 ports configured\n"); + exit(1); + } + + nr_neigh.type = NETROM_NEIGH; + /*nr_neigh.ndigis = 0; + + for (i = 0; i < AX25_MAX_DIGIS && rest[i][0] != '-' && rest[i][0] != '+'; i++) { + if (ax25_aton_entry(rest[i], nr_neigh.digipeaters[i].ax25_call) != 0) { + fprintf(stderr, "nrparms: routes: invalid callsign %s\n", rest[i]); + close(s); + exit(1); + } + nr_neigh.ndigis++; + } + */ + + op = rest[i + 0]; + quality = atoi(rest[i + 1]); + + if (op[0] != '+' && op[0] != '-') { + fprintf(stderr, "nrparms: routes: invalid operation %s\n", op); + close(s); + exit(1); + } + + if (quality < 1 || quality > 255) { + fprintf(stderr, "nrparms: routes: invalid quality %d\n", quality); + close(s); + exit(1); + } + + if ((dev = ax25_config_get_dev(port)) == NULL) { + fprintf(stderr, "nrparms: routes: invalid port name - %s\n", port); + close(s); + exit(1); + } + + strcpy(nr_neigh.device, dev); + + if (ax25_aton_entry(nodecall, nr_neigh.callsign.ax25_call) != 0) { + fprintf(stderr, "nrparms: routes: invalid callsign %s\n", nodecall); + close(s); + exit(1); + } + + nr_neigh.quality = quality; + + if (op[0] == '+') { + if (ioctl(s, SIOCADDRT, &nr_neigh) == -1) { + perror("nrparms: SIOCADDRT"); + close(s); + exit(1); + } + } else { + if (ioctl(s, SIOCDELRT, &nr_neigh) == -1) { + perror("nrparms: SIOCDELRT"); + close(s); + exit(1); + } + } +} + +int main(int argc, char *argv[]) +{ + int s; + + if (argc == 1) { + fprintf(stderr, "usage: nrparms -nodes|-routes|-version ...\n"); + return 1; + } + + if (strncmp(argv[1], "-v", 2) == 0) { + printf("nrparms: %s\n", VERSION); + return 0; + } + + if ((s = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + perror("nrparms: socket"); + return 1; + } + + if (strncmp(argv[1], "-n", 2) == 0) { + if (argc < 9) { + fprintf(stderr, nodes_usage); + close(s); + return 1; + } + nodes(s, argv[2], argv[3], argv[4], atoi(argv[5]), atoi(argv[6]), argv[7], argv[8], argv + 9); + close(s); + return 0; + } + + if (strncmp(argv[1], "-r", 2) == 0) { + if (argc < 6) { + fprintf(stderr, routes_usage); + close(s); + return 1; + } + routes(s, argv[2], argv[3], argv + 4); + close(s); + return 0; + } + + fprintf(stderr, "usage: nrparms -nodes|-routes|-version ...\n"); + + close(s); + + return 1; +} diff --git a/netrom/nrports b/netrom/nrports new file mode 100644 index 0000000..4faa359 --- /dev/null +++ b/netrom/nrports @@ -0,0 +1,7 @@ +# /etc/ax25/nrports +# +# The format of this file is: +# +# name callsign alias paclen description +# +netrom OH2BNS-10 #LNODE 235 Switch Port diff --git a/netrom/nrports.5 b/netrom/nrports.5 new file mode 100644 index 0000000..3449113 --- /dev/null +++ b/netrom/nrports.5 @@ -0,0 +1,56 @@ +.TH NRPORTS 5 "2 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +nrports \- NET/ROM port configuration file. +.SH DESCRIPTION +.LP +.B Nrports +is an ASCII file that contains information about each of the NET/ROM +ports that are to be used. When dealing with an NET/ROM utility such as +.B call, +it takes an optional argument that is the port name. This port name is a +reference to the line within +.B nrports, +which has the same name. The information on each line contains +enough information to bind the command to a particular NET/ROM +interface, this binding is done by matching the callsign on the line in +.B nrports +with the callsign of the port set by +.B ifconfig. +.LP +The +.B nrports +file may contain comments that begin with a # in the first column, or a port +description in the following format, each field being delimited by white space: +.sp +.RS +name callsign alias paclen description +.RE +.sp +The field descriptions are: +.sp +.RS +.TP 14 +.B name +this is the unique NET/ROM port identifier. +.TP 14 +.B callsign +the callsign of the NET/ROM interface to bind to. +.TP 14 +.B alias +this is the alias of the NET/ROM port. +.TP 14 +.B paclen +is the default packet size for this interface. +.TP 14 +.B description +a free format description of this interface, this field extends to the end +of the line. It may contain spaces. +.RE +.SH FILES +.LP +/etc/ax25/nrports +.SH "SEE ALSO" +.BR call (1), +.BR netrom (4), +.BR ifconfig (8), +.BR nrparms (8). diff --git a/netrom/nrsdrv.8 b/netrom/nrsdrv.8 new file mode 100644 index 0000000..fb27562 --- /dev/null +++ b/netrom/nrsdrv.8 @@ -0,0 +1,44 @@ +.TH NRSDRV 8 "22 December 1996" Linux "Linux System Managers Manual" +.SH NAME +nrsdrv \- KISS to NET/ROM serial converter +.SH SYNOPSIS +.B nrsdrv [-f] [-l] [-s speed] [-v] kissdev nrsdev +.SH DESCRIPTION +.LP +.B Nrsdrv +is a program designed to convert from the KISS protocol to the NET/ROM +serial protocol used by real NET/ROM's and TheNet's. The protocols are +fairly similar, although the NET/ROM serial protocol does include a one byte +checksum which KISS does not. +.sp 1 +Typically +.B nrsdrv +will be attached to one end of a pseudo-tty of which the other end has been +attached to a KISS capable program. The NET/ROM device will probably be a +real serial port attached to a TNC or a Hexipus. The full specification of +the NET/ROM serial protocol can be found in the original Software 2000 +documentation that accompanied NET/ROMs. +.SH OPTIONS +.TP 10 +.BI \-f +Flow control enabled for use with a Hexipus, the default is disabled. +See the file hexipus.txt in the source distribution for wiring details. + +.TP 10 +.BI \-l +Log messages to the system log, the default is not to. +.TP 10 +.BI "\-s speed" +Sets the speed of both interfaces. If no value is specified then no speed +will be set. +.TP 10 +.BI \-v +Display the version. +.SH BUGS +None known. +.SH "SEE ALSO" +.BR kill (1), +.BR stty (1), +.BR ax25 (4). +.SH AUTHOR +Jonathan Naylor G4KLX diff --git a/netrom/nrsdrv.c b/netrom/nrsdrv.c new file mode 100644 index 0000000..92b3d6a --- /dev/null +++ b/netrom/nrsdrv.c @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../pathnames.h" + +static int kissfd, nrsfd; +static int logging = FALSE; +static int debugging = FALSE; +static int flowcontrol = FALSE; +static char *kissdev, *nrsdev; + +#define NUL 000 +#define STX 002 +#define ETX 003 +#define DLE 020 + +#define NRS_WAIT 0 +#define NRS_DATA 1 +#define NRS_ESCAPE 2 +#define NRS_CKSUM 3 +static int nrs_state = NRS_WAIT; + +static unsigned char nrs_cksum = 0; + +static unsigned char nrs_rxbuffer[512]; +static int nrs_rxcount = 0; + +#define FEND 0300 +#define FESC 0333 +#define FESCEND 0334 +#define FESCESC 0335 + +#define KISS_WAIT 0 +#define KISS_CTRL 1 +#define KISS_DATA 2 +#define KISS_ESCAPE 3 +static int kiss_state = KISS_WAIT; + +static unsigned char kiss_rxbuffer[512]; +static int kiss_rxcount = 0; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + tty_unlock(kissdev); + tty_unlock(nrsdev); + + exit(0); +} + +static void key_rts(int fd) +{ + int status; + + if (!flowcontrol) + return; + + /* Wait for CTS to be low */ + while (1) { + /* Get CTS status */ + if (ioctl(fd, TIOCMGET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + return; + } + if (status & TIOCM_CTS) { + if (debugging) { + fprintf(stderr,"CTS high: waiting\n"); + } + ioctl(fd, TIOCMIWAIT, &status); + } else { + break; + } + } + + if (debugging) { + fprintf(stderr,"CTS low: keying RTS\n"); + } + status |= TIOCM_RTS | TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + } +} + +static void unkey_rts(int fd) +{ + int status; + + if (!flowcontrol) + return; + + if (debugging) { + fprintf(stderr,"Transmission finished: unkeying RTS\n"); + } + ioctl(fd, TIOCMGET, &status); + status &= ~TIOCM_RTS; + status |= TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &status) < 0) { + syslog(LOG_INFO|LOG_ERR, "TIOCMGET failed: flowcontrol disabled (%m)\n"); + flowcontrol = 0; + } +} + +static void nrs_esc(unsigned char *s, int len) +{ + static unsigned char buffer[512]; + unsigned char *ptr = buffer; + unsigned char csum = 0; + unsigned char c; + + *ptr++ = STX; + + while (len-- > 0) { + switch (c = *s++) { + case STX: + case ETX: + case DLE: + *ptr++ = DLE; + /* Fall through */ + default: + *ptr++ = c; + break; + } + + csum += c; + } + + *ptr++ = ETX; + *ptr++ = csum; + *ptr++ = NUL; + *ptr++ = NUL; + + key_rts(nrsfd); + write(nrsfd, buffer, ptr - buffer); + unkey_rts(nrsfd); +} + +static void kiss_esc(unsigned char *s, int len) +{ + static unsigned char buffer[512]; + unsigned char *ptr = buffer; + unsigned char c; + + *ptr++ = FEND; + *ptr++ = 0x00; /* KISS DATA */ + + while (len-- > 0) { + switch (c = *s++) { + case FESC: + *ptr++ = FESC; + *ptr++ = FESCESC; + break; + case FEND: + *ptr++ = FESC; + *ptr++ = FESCEND; + break; + default: + *ptr++ = c; + break; + } + } + + *ptr++ = FEND; + + write(kissfd, buffer, ptr - buffer); +} + +static void nrs_unesc(unsigned char *buffer, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (nrs_state) { + case NRS_WAIT: + if (buffer[i] == STX) { + nrs_state = NRS_DATA; + nrs_rxcount = 0; + nrs_cksum = 0; + } + break; + + case NRS_DATA: + switch (buffer[i]) { + case STX: /* !! */ + nrs_rxcount = 0; + nrs_cksum = 0; + break; + case DLE: + nrs_state = NRS_ESCAPE; + break; + case ETX: + nrs_state = NRS_CKSUM; + break; + default: + if (nrs_rxcount < 512) { + nrs_cksum += buffer[i]; + nrs_rxbuffer[nrs_rxcount++] = buffer[i]; + } + break; + } + break; + + case NRS_ESCAPE: + nrs_state = NRS_DATA; + if (nrs_rxcount < 512) { + nrs_cksum += buffer[i]; + nrs_rxbuffer[nrs_rxcount++] = buffer[i]; + } + break; + + case NRS_CKSUM: + if (buffer[i] == nrs_cksum) + kiss_esc(nrs_rxbuffer, nrs_rxcount); + nrs_state = NRS_WAIT; + nrs_cksum = 0; + nrs_rxcount = 0; + break; + } + } +} + +static void kiss_unesc(unsigned char *buffer, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (kiss_state) { + case KISS_WAIT: + if (buffer[i] == FEND) { + kiss_state = KISS_CTRL; + kiss_rxcount = 0; + } + break; + + case KISS_CTRL: + if ((buffer[i] & 0x0F) == 0x00) { + kiss_state = KISS_DATA; + kiss_rxcount = 0; + } else { + kiss_state = KISS_WAIT; + kiss_rxcount = 0; + } + break; + + case KISS_DATA: + switch (buffer[i]) { + case FEND: + if (kiss_rxcount > 2) + nrs_esc(kiss_rxbuffer, kiss_rxcount); + kiss_state = KISS_WAIT; + kiss_rxcount = 0; + break; + case FESC: + kiss_state = KISS_ESCAPE; + break; + default: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = buffer[i]; + break; + } + break; + + case KISS_ESCAPE: + kiss_state = KISS_DATA; + switch (buffer[i]) { + case FESCESC: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = FESC; + break; + case FESCEND: + if (kiss_rxcount < 512) + kiss_rxbuffer[kiss_rxcount++] = FEND; + break; + } + break; + } + } +} + +int main(int argc, char *argv[]) +{ + static char buffer[512]; + unsigned int speed = 0; + fd_set read_fd; + int c, n; + + while ((c = getopt(argc, argv, "dfls:v")) != -1) { + switch (c) { + case 'd': + debugging = TRUE; + break; + case 'f': + flowcontrol = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 's': + if ((speed = atoi(optarg)) <= 0) { + fprintf(stderr, "nrsdrv: invalid speed %s\n", optarg); + return 1; + } + break; + case 'v': + printf("kissattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: nrsdrv [-f] [-l] [-s speed] [-v] kisstty nrstty\n"); + return 1; + } + } + + if (debugging) { + fprintf(stderr,"Flow control %s\n", + flowcontrol ? "enabled" : "disabled"); + } + + if ((argc - optind) != 2) { + fprintf(stderr, "usage: nrsdrv [-f] [-l] [-s speed] [-v] kisstty nrstty\n"); + return 1; + } + + kissdev = argv[optind + 0]; + nrsdev = argv[optind + 1]; + + if (tty_is_locked(kissdev)) { + fprintf(stderr, "nrsdrv: device %s already in use\n", argv[optind]); + return 1; + } + + if (tty_is_locked(nrsdev)) { + fprintf(stderr, "nrsdrv: device %s already in use\n", argv[optind + 1]); + return 1; + } + + if ((kissfd = open(kissdev, O_RDWR)) == -1) { + perror("nrsdrv: open kiss device"); + return 1; + } + + if ((nrsfd = open(nrsdev, O_RDWR)) == -1) { + perror("nrsdrv: open nrs device"); + return 1; + } + + tty_lock(kissdev); + tty_lock(nrsdev); + + if (!tty_raw(kissfd, FALSE)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (!tty_raw(nrsfd, FALSE)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (speed != 0 && !tty_speed(kissfd, speed)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (speed != 0 && !tty_speed(nrsfd, speed)) { + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (logging) { + openlog("nrsdrv", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "KISS device %s connected to NRS device %s\n", argv[optind + 0], argv[optind + 1]); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, terminate); + + /* + * Become a daemon if we can. + */ + if (!daemon_start(FALSE)) { + fprintf(stderr, "nrsdrv: cannot become a daemon\n"); + tty_unlock(kissdev); + tty_unlock(nrsdev); + return 1; + } + + if (flowcontrol) { + unkey_rts(nrsfd); + } + + c = ((kissfd > nrsfd) ? kissfd : nrsfd) + 1; + + for (;;) { + FD_ZERO(&read_fd); + + FD_SET(kissfd, &read_fd); + FD_SET(nrsfd, &read_fd); + + n = select(c, &read_fd, NULL, NULL, NULL); + + if (FD_ISSET(kissfd, &read_fd)) { + if ((n = read(kissfd, buffer, 512)) <= 0) { + if (logging) { + syslog(LOG_INFO, "terminating on KISS device closure\n"); + closelog(); + } + break; + } + kiss_unesc(buffer, n); + } + + if (FD_ISSET(nrsfd, &read_fd)) { + if ((n = read(nrsfd, buffer, 512)) <= 0) { + if (logging) { + syslog(LOG_INFO, "terminating on NRS device closure\n"); + closelog(); + } + break; + } + nrs_unesc(buffer, n); + } + } + + tty_unlock(kissdev); + tty_unlock(nrsdev); + + return 0; +} -- cgit v1.2.3