summaryrefslogtreecommitdiffstats
path: root/rose
diff options
context:
space:
mode:
Diffstat (limited to 'rose')
-rw-r--r--rose/Makefile.am19
-rw-r--r--rose/Makefile.in471
-rw-r--r--rose/rose.444
-rw-r--r--rose/rsattach.833
-rw-r--r--rose/rsattach.c219
-rw-r--r--rose/rsdwnlnk.858
-rw-r--r--rose/rsdwnlnk.c272
-rw-r--r--rose/rsmemsiz.c204
-rw-r--r--rose/rsparms.864
-rw-r--r--rose/rsparms.c256
-rw-r--r--rose/rsports7
-rw-r--r--rose/rsports.552
-rw-r--r--rose/rsuplnk.863
-rw-r--r--rose/rsuplnk.c288
14 files changed, 2050 insertions, 0 deletions
diff --git a/rose/Makefile.am b/rose/Makefile.am
new file mode 100644
index 0000000..3cbb2c8
--- /dev/null
+++ b/rose/Makefile.am
@@ -0,0 +1,19 @@
+
+etcfiles = rsports
+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 = rsattach rsdwnlnk rsmemsiz rsparms rsuplnk
+
+sbin_SCRIPTS = rsusers.sh
+
+
+man_MANS = rose.4 rsports.5 rsattach.8 rsparms.8 rsdwnlnk.8 rsuplnk.8
+
+EXTRA_DIST = $(man_MANS) $(etcfiles)
diff --git a/rose/Makefile.in b/rose/Makefile.in
new file mode 100644
index 0000000..0ded273
--- /dev/null
+++ b/rose/Makefile.in
@@ -0,0 +1,471 @@
+# 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 = rsports
+etcdir = $(sysconfdir)/ax25
+
+sbin_PROGRAMS = rsattach rsdwnlnk rsmemsiz rsparms rsuplnk
+
+sbin_SCRIPTS = rsusers.sh
+
+man_MANS = rose.4 rsports.5 rsattach.8 rsparms.8 rsdwnlnk.8 rsuplnk.8
+
+EXTRA_DIST = $(man_MANS) $(etcfiles)
+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@
+rsattach_SOURCES = rsattach.c
+rsattach_OBJECTS = rsattach.o
+rsattach_LDADD = $(LDADD)
+rsattach_DEPENDENCIES =
+rsattach_LDFLAGS =
+rsdwnlnk_SOURCES = rsdwnlnk.c
+rsdwnlnk_OBJECTS = rsdwnlnk.o
+rsdwnlnk_LDADD = $(LDADD)
+rsdwnlnk_DEPENDENCIES =
+rsdwnlnk_LDFLAGS =
+rsmemsiz_SOURCES = rsmemsiz.c
+rsmemsiz_OBJECTS = rsmemsiz.o
+rsmemsiz_LDADD = $(LDADD)
+rsmemsiz_DEPENDENCIES =
+rsmemsiz_LDFLAGS =
+rsparms_SOURCES = rsparms.c
+rsparms_OBJECTS = rsparms.o
+rsparms_LDADD = $(LDADD)
+rsparms_DEPENDENCIES =
+rsparms_LDFLAGS =
+rsuplnk_SOURCES = rsuplnk.c
+rsuplnk_OBJECTS = rsuplnk.o
+rsuplnk_LDADD = $(LDADD)
+rsuplnk_DEPENDENCIES =
+rsuplnk_LDFLAGS =
+SCRIPTS = $(sbin_SCRIPTS)
+
+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 = rsattach.c rsdwnlnk.c rsmemsiz.c rsparms.c rsuplnk.c
+OBJECTS = rsattach.o rsdwnlnk.o rsmemsiz.o rsparms.o rsuplnk.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 rose/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:
+
+rsattach: $(rsattach_OBJECTS) $(rsattach_DEPENDENCIES)
+ @rm -f rsattach
+ $(LINK) $(rsattach_LDFLAGS) $(rsattach_OBJECTS) $(rsattach_LDADD) $(LIBS)
+
+rsdwnlnk: $(rsdwnlnk_OBJECTS) $(rsdwnlnk_DEPENDENCIES)
+ @rm -f rsdwnlnk
+ $(LINK) $(rsdwnlnk_LDFLAGS) $(rsdwnlnk_OBJECTS) $(rsdwnlnk_LDADD) $(LIBS)
+
+rsmemsiz: $(rsmemsiz_OBJECTS) $(rsmemsiz_DEPENDENCIES)
+ @rm -f rsmemsiz
+ $(LINK) $(rsmemsiz_LDFLAGS) $(rsmemsiz_OBJECTS) $(rsmemsiz_LDADD) $(LIBS)
+
+rsparms: $(rsparms_OBJECTS) $(rsparms_DEPENDENCIES)
+ @rm -f rsparms
+ $(LINK) $(rsparms_LDFLAGS) $(rsparms_OBJECTS) $(rsparms_LDADD) $(LIBS)
+
+rsuplnk: $(rsuplnk_OBJECTS) $(rsuplnk_DEPENDENCIES)
+ @rm -f rsuplnk
+ $(LINK) $(rsuplnk_LDFLAGS) $(rsuplnk_OBJECTS) $(rsuplnk_LDADD) $(LIBS)
+
+install-sbinSCRIPTS: $(sbin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_SCRIPTS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \
+ else if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; fi; \
+ done
+
+uninstall-sbinSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ list='$(sbin_SCRIPTS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+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 = rose
+
+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
+rsattach.o: rsattach.c ../config.h ../pathnames.h
+rsdwnlnk.o: rsdwnlnk.c ../config.h
+rsmemsiz.o: rsmemsiz.c
+rsparms.o: rsparms.c ../config.h ../pathnames.h
+rsuplnk.o: rsuplnk.c ../config.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-sbinSCRIPTS
+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-sbinSCRIPTS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(MANS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(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 uninstall-sbinSCRIPTS \
+install-sbinSCRIPTS 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/rose/rose.4 b/rose/rose.4
new file mode 100644
index 0000000..e02d3a4
--- /dev/null
+++ b/rose/rose.4
@@ -0,0 +1,44 @@
+.TH ROSE 4 "27 August 1996" Linux "Linux Programmer's Manual"
+.SH NAME
+AF_ROSE \- Rose amateur packet radio protocol family
+.SH DESCRIPTION
+.LP
+.B Rose
+is a protocol used extensively by radio amateurs. The Linux
+Rose protocol family permits access to these protocols via
+the standard networking
+.B socket
+metaphor.
+.LP
+The Rose protocol layer only supports connected mode.
+.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 Rose).
+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
+Rose addresses consist of 10 digits. These are encoded into a sockaddr_rose
+structure which is provided to the relevant system calls.
+.LP
+Rose 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
+Rose supports the following socket options for SOL_ROSE. ROSE_T1 is the
+T11/T21 timer in 1/10ths of a second, ROSE_T2 is the T12/T22 timer in
+1/10ths of a second. ROSE_T3, is the T13/T23 timer in 1/10ths of a second.
+It is possible for an application to request that the Rose layer return
+the Rose header as well as the application data, this is done via the
+ROSE_HDRINCL socket option.
+.SH "SEE ALSO"
+.BR call (1),
+.BR socket (2),
+.BR setsockopt(2),
+.BR getsockopt(2),
+.BR rsports (5),
+.BR rsctl (8),
+.BR rsparms (8).
+.LP
+.SH AUTHOR
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
diff --git a/rose/rsattach.8 b/rose/rsattach.8
new file mode 100644
index 0000000..1a67769
--- /dev/null
+++ b/rose/rsattach.8
@@ -0,0 +1,33 @@
+.TH RSATTACH 8 "27 August 1996" Linux "Linux System Managers Manual"
+.SH NAME
+rsattach \- Start a Rose interface
+.SH SYNOPSIS
+.B rsattach [-i inetaddr] [-v] port
+.SH DESCRIPTION
+.LP
+.B Rsattach
+takes many of the parameters for the port from the rsports(5) file. The port
+argument is the name of a port as given in the rsports(5) file.
+.LP
+.B Rsattach
+tries to find the free Rose device in the system. The device name checked is
+rose0. If no free Rose 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 \-v
+Display the version.
+.SH "SEE ALSO"
+.BR rose (4),
+.BR rsparms (4),
+.BR rsports (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 <g4klx@g4klx.demon.co.uk>
diff --git a/rose/rsattach.c b/rose/rsattach.c
new file mode 100644
index 0000000..3d98858
--- /dev/null
+++ b/rose/rsattach.c
@@ -0,0 +1,219 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <netdb.h>
+
+#include <sys/ioctl.h>
+
+#include <sys/socket.h>
+/* #include <linux/netdevice.h> */
+#include <net/if.h>
+#include <net/if_arp.h>
+/* #include <linux/sockios.h> */
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+
+#include <config.h>
+
+#include "../pathnames.h"
+
+char *address;
+int mtu = 128;
+
+int readconfig(char *port)
+{
+ FILE *fp;
+ char buffer[90], *s;
+ int n = 0;
+
+ if ((fp = fopen(CONF_RSPORTS_FILE, "r")) == NULL) {
+ fprintf(stderr, "rsattach: cannot open rsports 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, "rsattach: unable to parse line %d of the rsports file\n", n);
+ return FALSE;
+ }
+
+ if (strcmp(s, port) != 0)
+ continue;
+
+ if ((s = strtok(NULL, " \t\r\n")) == NULL) {
+ fprintf(stderr, "rsattach: unable to parse line %d of the rsports file\n", n);
+ return FALSE;
+ }
+
+ address = strdup(s);
+
+ fclose(fp);
+
+ return TRUE;
+ }
+
+ fclose(fp);
+
+ fprintf(stderr, "rsattach: cannot find port %s in rsports\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("rsattach: socket");
+ return FALSE;
+ }
+
+ for (i = 0; i < 6; i++) {
+ sprintf(dev, "rose%d", i);
+ strcpy(ifr.ifr_name, dev);
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ perror("rsattach: 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 addr[5];
+ int fd;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("rsattach: 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("rsattach: SIOCSIFADDR");
+ return FALSE;
+ }
+ }
+
+ if (rose_aton(address, addr) == -1)
+ return FALSE;
+
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ROSE;
+ memcpy(ifr.ifr_hwaddr.sa_data, addr, 5);
+
+ if (ioctl(fd, SIOCSIFHWADDR, &ifr) != 0) {
+ perror("rsattach: SIOCSIFHWADDR");
+ return FALSE;
+ }
+
+ ifr.ifr_mtu = mtu;
+
+ if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
+ perror("rsattach: SIOCSIFMTU");
+ return FALSE;
+ }
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ perror("rsattach: 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("rsattach: 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, "rsattach: invalid internet name/address - %s\n", optarg);
+ return 1;
+ }
+ break;
+ case 'v':
+ printf("rsattach: %s\n", VERSION);
+ return 0;
+ case ':':
+ case '?':
+ fprintf(stderr, "usage: rsattach [-i inetaddr] [-v] port\n");
+ return 1;
+ }
+ }
+
+ if ((argc - optind) != 1) {
+ fprintf(stderr, "usage: rsattach [-i inetaddr] [-v] port\n");
+ return 1;
+ }
+
+ if (!readconfig(argv[optind]))
+ return 1;
+
+ if (!getfreedev(dev)) {
+ fprintf(stderr, "rsattach: cannot find free Rose device\n");
+ return 1;
+ }
+
+ if (!startiface(dev, hp))
+ return 1;
+
+ printf("Rose port %s bound to device %s\n", argv[optind], dev);
+
+ return 0;
+}
diff --git a/rose/rsdwnlnk.8 b/rose/rsdwnlnk.8
new file mode 100644
index 0000000..f0d4c2d
--- /dev/null
+++ b/rose/rsdwnlnk.8
@@ -0,0 +1,58 @@
+.TH RSDWNLNK 8 "29 April 1997" Linux "Linux Programmer's Manual"
+.SH NAME
+rsdwnlnk \- User exit from the ROSE network.
+.SH SYNOPSIS
+.B rsdwnlnk <port> <call>
+.SH DESCRIPTION
+.LP
+The
+.B rdwnplnk
+program allows a user to leave the ROSE network using the standard
+pseudo-digipeating method. Recent Linux kernels are aware of this form of
+operation and the
+.B ax25d
+program can create such connections. The normal mode of operation of a
+ROSE switch is to have one ROSE address (ie port) per physical AX.25 port.
+Therefore ROSE users coming in on a given ROSE port will come out of the
+associated AX.25 port.
+.LP
+To use
+.B rsdwnlnk
+you need an entry in
+.B ax25d.conf
+to listen for incoming ROSE connections to any callsigns that are not
+matched by the more specific ROSE entries. In the example below, I will be
+listening for ROSE connections on my ROSE port rs144, the exiting AX.25
+connection will be via the associated AX.25 port, 144, using the callsign
+KE4GAJ-10. Please note that the callsign should be on the same line as the
+rest of the command, it may be wrapped onto the next line on your screen.
+.LP
+#
+.br
+{* VIA rs144}
+.br
+NOCALL * * * * * * L
+.br
+default * * * * * * - root /usr/sbin/rsdwnlnk rsdwnlnk 144 KE4GAJ-10
+.br
+#
+.LP
+There would typically be one
+.B rsdwnlnk
+per ROSE port. The associated program for entering a ROSE network is
+.B rsuplnk.
+.LP
+All errors generated by
+.B rsdwnlnk
+are written to the system debug log file.
+.SH FILES
+.br
+/etc/ax25/axports
+.SH "SEE ALSO"
+.BR rose (4),
+.BR ax25d.conf (5),
+.BR ax25d (8),
+.BR rsuplnk (8),
+.BR rose_call (8).
+.SH AUTHOR
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
diff --git a/rose/rsdwnlnk.c b/rose/rsdwnlnk.c
new file mode 100644
index 0000000..5729d99
--- /dev/null
+++ b/rose/rsdwnlnk.c
@@ -0,0 +1,272 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <syslog.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+
+#include <config.h>
+
+#define AX25_HBIT 0x80
+
+void alarm_handler(int sig)
+{
+}
+
+int main(int argc, char **argv)
+{
+ unsigned char buffer[512], *addr;
+ fd_set read_fd;
+ int n = 0, s, addrlen, yes = 1;
+ struct full_sockaddr_ax25 axbind, axconnect;
+ struct sockaddr_rose rosesock, rosepeer;
+
+ openlog("rsdwnlnk", LOG_PID, LOG_DAEMON);
+
+ /*
+ * Arguments should be "rsdwnlnk ax25port ax25call"
+ */
+ if (argc != 3) {
+ syslog(LOG_ERR, "invalid number of parameters\n");
+ closelog();
+ return 1;
+ }
+
+ if (ax25_config_load_ports() == 0) {
+ syslog(LOG_ERR, "problem with axports file\n");
+ closelog();
+ return 1;
+ }
+
+ addrlen = sizeof(struct sockaddr_rose);
+
+ if (getsockname(STDIN_FILENO, (struct sockaddr *)&rosesock, &addrlen) == -1) {
+ syslog(LOG_ERR, "cannot getsockname - %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+
+ addrlen = sizeof(struct sockaddr_rose);
+
+ if (getpeername(STDIN_FILENO, (struct sockaddr *)&rosepeer, &addrlen) == -1) {
+ syslog(LOG_ERR, "cannot getpeername - %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+
+ if (setsockopt(STDIN_FILENO, SOL_ROSE, ROSE_QBITINCL, &yes, sizeof(yes)) == -1) {
+ syslog(LOG_ERR, "cannot setsockopt(ROSE_QBITINCL) - %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+
+ /*
+ * Parse the passed values for correctness.
+ */
+ axbind.fsa_ax25.sax25_family = AF_AX25;
+ axbind.fsa_ax25.sax25_ndigis = 1;
+ axbind.fsa_ax25.sax25_call = rosepeer.srose_call;
+
+ if ((addr = ax25_config_get_addr(argv[1])) == NULL) {
+ syslog(LOG_ERR, "invalid AX.25 port name - %s\n", argv[1]);
+ closelog();
+ return 1;
+ }
+
+ if (ax25_aton_entry(addr, axbind.fsa_digipeater[0].ax25_call) == -1) {
+ syslog(LOG_ERR, "invalid AX.25 port callsign - %s\n", argv[1]);
+ closelog();
+ return 1;
+ }
+
+ axconnect.fsa_ax25.sax25_family = AF_AX25;
+ axconnect.fsa_ax25.sax25_call = rosesock.srose_call;
+
+ /*
+ * The path at the far end has a digi in it.
+ */
+ if (rosepeer.srose_ndigis == 1) {
+ axconnect.fsa_digipeater[n] = rosepeer.srose_digi;
+ axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT;
+ n++;
+ }
+
+ /*
+ * Incoming call has a different DNIC
+ */
+ if (memcmp(rosepeer.srose_addr.rose_addr, rosesock.srose_addr.rose_addr, 2) != 0) {
+ addr = rose_ntoa(&rosepeer.srose_addr);
+ addr[4] = '\0';
+ if (ax25_aton_entry(addr, axconnect.fsa_digipeater[n].ax25_call) == -1) {
+ syslog(LOG_ERR, "invalid callsign - %s\n", addr);
+ closelog();
+ return 1;
+ }
+ axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT;
+ n++;
+ }
+
+ /*
+ * Put the remote address sans DNIC into the digi chain.
+ */
+ addr = rose_ntoa(&rosepeer.srose_addr);
+ if (ax25_aton_entry(addr + 4, axconnect.fsa_digipeater[n].ax25_call) == -1) {
+ syslog(LOG_ERR, "invalid callsign - %s\n", addr + 4);
+ closelog();
+ return 1;
+ }
+ axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT;
+ n++;
+
+ /*
+ * And my local ROSE callsign.
+ */
+ if (ax25_aton_entry(argv[2], axconnect.fsa_digipeater[n].ax25_call) == -1) {
+ syslog(LOG_ERR, "invalid callsign - %s\n", argv[2]);
+ closelog();
+ return 1;
+ }
+ axconnect.fsa_digipeater[n].ax25_call[6] |= AX25_HBIT;
+ n++;
+
+ /*
+ * A digi has been specified for this end.
+ */
+ if (rosesock.srose_ndigis == 1) {
+ axconnect.fsa_digipeater[n] = rosesock.srose_digi;
+ n++;
+ }
+
+ axconnect.fsa_ax25.sax25_ndigis = n;
+
+ addrlen = sizeof(struct full_sockaddr_ax25);
+
+ /*
+ * Open the socket into the kernel.
+ */
+ if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "cannot open AX.25 socket, %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+#ifdef HAVE_AX25_IAMDIGI
+ if (setsockopt(s, SOL_AX25, AX25_IAMDIGI, &yes, sizeof(yes)) == -1) {
+ syslog(LOG_ERR, "cannot setsockopt(AX25_IAMDIGI), %s\n", strerror(errno));
+ close(s);
+ closelog();
+ return 1;
+ }
+#endif /* HAVE_AX25_IAMDIGI */
+#ifdef HAVE_AX25_PIDINCL
+ if (setsockopt(s, SOL_AX25, AX25_PIDINCL, &yes, sizeof(yes)) == -1) {
+ syslog(LOG_ERR, "cannot setsockopt(AX25_PIDINCL), %s\n", strerror(errno));
+ close(s);
+ closelog();
+ return 1;
+ }
+#endif /* HAVE_AX25_PIDINCL */
+ /*
+ * Set our AX.25 callsign and AX.25 port callsign accordingly.
+ */
+ if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) {
+ syslog(LOG_ERR, "cannot bind AX.25 socket, %s\n", strerror(errno));
+ close(s);
+ closelog();
+ return 1;
+ }
+
+ /*
+ * If no response in 60 seconds, go away.
+ */
+ alarm(60);
+
+ signal(SIGALRM, alarm_handler);
+
+ /*
+ * Lets try and connect to the far end.
+ */
+ if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ strcpy(buffer, "*** Connection refused\r");
+ break;
+ case ENETUNREACH:
+ strcpy(buffer, "*** No known route\r");
+ break;
+ case EINTR:
+ strcpy(buffer, "*** Connection timed out\r");
+ break;
+ default:
+ sprintf(buffer, "ERROR: cannot connect to AX.25 callsign, %s\r", strerror(errno));
+ break;
+ }
+
+ close(s);
+
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+
+ sleep(20);
+
+ return 0;
+ }
+
+ /*
+ * We got there.
+ */
+ alarm(0);
+
+ strcpy(buffer, "*** Connected\r");
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+
+ /*
+ * Loop until one end of the connection goes away.
+ */
+ for (;;) {
+ FD_ZERO(&read_fd);
+ FD_SET(STDIN_FILENO, &read_fd);
+ FD_SET(s, &read_fd);
+
+ select(s + 1, &read_fd, NULL, NULL, NULL);
+
+ if (FD_ISSET(s, &read_fd)) {
+ if ((n = read(s, buffer + 2, 512)) == -1)
+ break;
+ if (buffer[2] == 0xF0) {
+ buffer[2] = 0;
+ write(STDOUT_FILENO, buffer + 2, n);
+ } else {
+ buffer[0] = 1; /* Set Q Bit on */
+ buffer[1] = 0x7F; /* Q Bit escape */
+ write(STDOUT_FILENO, buffer, n + 2);
+ }
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &read_fd)) {
+ if ((n = read(STDIN_FILENO, buffer, 512)) == -1) {
+ close(s);
+ break;
+ }
+ if (buffer[0] == 0) { /* Q Bit not set */
+ buffer[0] = 0xF0;
+ write(s, buffer, n);
+ } else {
+ /* Lose the leading 0x7F */
+ write(s, buffer + 2, n - 2);
+ }
+ }
+ }
+
+ closelog();
+
+ return 0;
+}
diff --git a/rose/rsmemsiz.c b/rose/rsmemsiz.c
new file mode 100644
index 0000000..6c1cec9
--- /dev/null
+++ b/rose/rsmemsiz.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+enum meminfo_row { meminfo_main = 0,
+ meminfo_swap };
+
+enum meminfo_col { meminfo_total = 0, meminfo_used, meminfo_free,
+ meminfo_shared, meminfo_buffers, meminfo_cached
+};
+
+unsigned read_total_main(void);
+
+/*
+ * This code is slightly modified from the procps package.
+ */
+
+#define UPTIME_FILE "/proc/uptime"
+#define LOADAVG_FILE "/proc/loadavg"
+#define MEMINFO_FILE "/proc/meminfo"
+
+static char buf[300];
+
+/* This macro opens FILE only if necessary and seeks to 0 so that successive
+ calls to the functions are more efficient. It also reads the current
+ contents of the file into the global buf.
+*/
+#define FILE_TO_BUF(FILE) { \
+ static int n, fd = -1; \
+ if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \
+ fprintf(stdout, "ERROR: file %s, %s\r", FILE, strerror(errno)); \
+ close(fd); \
+ return 0; \
+ } \
+ lseek(fd, 0L, SEEK_SET); \
+ if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \
+ fprintf(stdout, "ERROR: file %s, %s\r", FILE, strerror(errno)); \
+ close(fd); \
+ fd = -1; \
+ return 0; \
+ } \
+ buf[n] = '\0'; \
+}
+
+#define SET_IF_DESIRED(x,y) if (x) *(x) = (y) /* evals 'x' twice */
+
+int uptime(double *uptime_secs, double *idle_secs) {
+ double up=0, idle=0;
+
+ FILE_TO_BUF(UPTIME_FILE)
+ if (sscanf(buf, "%lf %lf", &up, &idle) < 2) {
+ fprintf(stdout, "ERROR: Bad data in %s\r", UPTIME_FILE);
+ return 0;
+ }
+ SET_IF_DESIRED(uptime_secs, up);
+ SET_IF_DESIRED(idle_secs, idle);
+ return up; /* assume never be zero seconds in practice */
+}
+
+int loadavg(double *av1, double *av5, double *av15) {
+ double avg_1=0, avg_5=0, avg_15=0;
+
+ FILE_TO_BUF(LOADAVG_FILE)
+ if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) {
+ fprintf(stdout, "ERROR: Bad data in %s\r", LOADAVG_FILE);
+ return 0;
+ }
+ SET_IF_DESIRED(av1, avg_1);
+ SET_IF_DESIRED(av5, avg_5);
+ SET_IF_DESIRED(av15, avg_15);
+ return 1;
+}
+
+/* The following /proc/meminfo parsing routine assumes the following format:
+ [ <label> ... ] # header lines
+ [ <label> ] <num> [ <num> ... ] # table rows
+ [ repeats of above line ]
+
+ Any lines with fewer <num>s than <label>s get trailing <num>s set to zero.
+ The return value is a NULL terminated unsigned** which is the table of
+ numbers without labels. Convenient enumeration constants for the major and
+ minor dimensions are available in the header file. Note that this version
+ requires that labels do not contain digits. It is readily extensible to
+ labels which do not *begin* with digits, though.
+*/
+
+#define MAX_ROW 3 /* these are a little liberal for flexibility */
+#define MAX_COL 7
+
+unsigned** meminfo(void) {
+ static unsigned *row[MAX_ROW + 1]; /* row pointers */
+ static unsigned num[MAX_ROW * MAX_COL]; /* number storage */
+ char *p;
+ int i, j, k, l;
+
+ FILE_TO_BUF(MEMINFO_FILE)
+ if (!row[0]) /* init ptrs 1st time through */
+ for (i=0; i < MAX_ROW; i++) /* std column major order: */
+ row[i] = num + MAX_COL*i; /* A[i][j] = A + COLS*i + j */
+ p = buf;
+ for (i=0; i < MAX_ROW; i++) /* zero unassigned fields */
+ for (j=0; j < MAX_COL; j++)
+ row[i][j] = 0;
+ for (i=0; i < MAX_ROW && *p; i++) { /* loop over rows */
+ while(*p && !isdigit(*p)) p++; /* skip chars until a digit */
+ for (j=0; j < MAX_COL && *p; j++) { /* scanf column-by-column */
+ l = sscanf(p, "%u%n", row[i] + j, &k);
+ p += k; /* step over used buffer */
+ if (*p == '\n' || l < 1) /* end of line/buffer */
+ break;
+ }
+ }
+/* row[i+1] = NULL; terminate the row list, currently unnecessary */
+ return row; /* NULL return ==> error */
+}
+
+
+/*
+ * by Heikki Hannikainen <hessu@pspt.fi>
+ * The following was mostly learnt from the procps package and the
+ * gnu sh-utils (mainly uname).
+ */
+
+int main(int argc, char **argv)
+{
+ int upminutes, uphours, updays;
+ double uptime_secs, idle_secs;
+ double av[3];
+ unsigned **mem;
+ char *p;
+ struct utsname name;
+ time_t t;
+
+ fprintf(stdout, "Linux/ROSE 001. System parameters\r");
+
+ time(&t);
+ p = ctime(&t);
+ p[24] = '\r';
+ fprintf(stdout, "System time: %s", p);
+
+ if (uname(&name) == -1)
+ fprintf(stdout, "Cannot get system name\r");
+ else {
+ fprintf(stdout, "Hostname: %s\r", name.nodename);
+ fprintf(stdout, "Operating system: %s %s (%s)\r", name.sysname,
+ name.release, name.machine);
+ }
+
+ /* read and calculate the amount of uptime and format it nicely */
+ uptime(&uptime_secs, &idle_secs);
+ updays = (int) uptime_secs / (60*60*24);
+ upminutes = (int) uptime_secs / 60;
+ uphours = upminutes / 60;
+ uphours = uphours % 24;
+ upminutes = upminutes % 60;
+ fprintf(stdout, "Uptime: ");
+
+ if (updays)
+ fprintf(stdout, "%d day%s, ", updays, (updays != 1) ? "s" : "");
+
+ if (uphours)
+ fprintf(stdout, "%d hour%s ", uphours, (uphours != 1) ? "s" : "");
+ fprintf(stdout, "%d minute%s\r", upminutes, (upminutes != 1) ? "s" : "");
+
+ loadavg(&av[0], &av[1], &av[2]);
+ fprintf(stdout, "Load average: %.2f, %.2f, %.2f\r", av[0], av[1], av[2]);
+
+ if (!(mem = meminfo()) || mem[meminfo_main][meminfo_total] == 0) {
+ /* cannot normalize mem usage */
+ fprintf(stdout, "Cannot get memory information!\r");
+ } else {
+ fprintf(stdout, "Memory: %5d KB available, %5d KB used, %5d KB free\r",
+ mem[meminfo_main][meminfo_total] >> 10,
+ (mem[meminfo_main][meminfo_used] -
+ mem[meminfo_main][meminfo_buffers] -
+ mem[meminfo_total][meminfo_cached]) >> 10,
+ (mem[meminfo_main][meminfo_free] +
+ mem[meminfo_main][meminfo_buffers] +
+ mem[meminfo_total][meminfo_cached]) >> 10);
+
+ fprintf(stdout, "Swap: %5d KB available, %5d KB used, %5d KB free\r",
+ mem[meminfo_swap][meminfo_total] >> 10,
+ mem[meminfo_swap][meminfo_used] >> 10,
+ mem[meminfo_swap][meminfo_free] >> 10);
+ }
+
+ fprintf(stdout, "\r");
+ fflush(stdout);
+
+ while (1) {
+ if (read(STDIN_FILENO, av, 3) <= 0)
+ break;
+ }
+
+ return 0;
+}
diff --git a/rose/rsparms.8 b/rose/rsparms.8
new file mode 100644
index 0000000..aeadc20
--- /dev/null
+++ b/rose/rsparms.8
@@ -0,0 +1,64 @@
+.TH RSPARMS 8 "25 July 1997" Linux "Linux System Managers Manual"
+.SH NAME
+rsparms \- Configure the Rose interface.
+.SH SYNOPSIS
+.B rsparms -nodes add|del address[/mask] port neigh [digis...]
+.LP
+.B rsparms -nodes list
+.LP
+.B rsparms -call <callsign>|none
+.LP
+.B rsparms -version
+.SH DESCRIPTION
+.LP
+This program is used to manipulate the routing tables of the Rose network
+layer. To set up a new route to a Rose 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 rsparms -nodes add 2080192303 144 F1OAT-11
+.LP
+This creates a new route to a distant node with the address 2080192303 and
+the packets for that node should be sent on AX.25 port 144 to my immediate
+neighbour F1OAT-11 without going through any digi-praters. For
+example to set up the same node but via a digi-peater I would use:
+.LP
+.B rsparms -nodes add 2080192303 144 F1OAT-11 F6PRA-9
+.LP
+It is also possible to remove a route to a distant node with the same
+command except that the \(lqadd\(rq is replaced by a \(lqdel\(rq. The other
+parameters must also be present. If the node has no 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.
+.LP
+You may list the configured Rose routes using the following syntax:
+.LP
+.B rsparms -nodes list
+.LP
+This program may also be used to set up a common AX.25 level 2 callsign that
+will be used for the ROSE node. By default no special level 2 callsign is
+set, but setting it will replace any existing level 2 callsign and register
+another one. Setting the callsign to \(lqnone\(rq will remove the level 2
+callsign. For example:
+.LP
+.B rsparms -call VK2KTJ-10
+.LP
+would set the callsign used by Rose internode traffic to VK2KTJ-10.
+.SH OPTIONS
+.TP 10
+.BI \-version
+Display the version information.
+.SH FILES
+.LP
+/etc/ax25/axports
+.br
+/etc/ax25/rsports
+.SH "SEE ALSO"
+.BR call (1),
+.BR rose (4),
+.BR axports (5),
+.BR rsports (5),
+.BR rsctl (8),
+.BR rsparms (8).
+.SH AUTHOR
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
diff --git a/rose/rsparms.c b/rose/rsparms.c
new file mode 100644
index 0000000..86e0935
--- /dev/null
+++ b/rose/rsparms.c
@@ -0,0 +1,256 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/rsconfig.h>
+
+#include <config.h>
+
+#include "../pathnames.h"
+
+char nodes_usage[] = "usage: rsparms -node add|del nodeaddr[/mask] port neighbour [digis...]\n rsparms -node list\n";
+
+/* print the Rose neighbour whose number is supplied */
+void printnb(char *neigh)
+{
+ FILE* fp;
+ char addr[10], callsign[10], port[10], digi[10];
+ char buff[80];
+ int args;
+
+ if ((fp=fopen(PROC_RS_NEIGH_FILE,"r"))==NULL) {
+ fprintf(stderr,"rsparms: Couldn't open %s file\n",PROC_RS_NEIGH_FILE);
+ exit(1);
+ }
+
+ while(fgets(buff, 80, fp)) {
+ addr[0]=(char)NULL; callsign[0]=(char)NULL;
+ port[0]=(char)NULL; digi[0]=(char)NULL;
+
+ args=sscanf(buff,"%9s %9s %9s %*s %*s %*s %*s %*s %*s %9s",addr,callsign,port,digi);
+
+ if (args==4) { /* We have a digi */
+ if (strcmp(addr,neigh)==0)
+ printf("%-6s %-9s via %-9s",port,callsign,digi);
+ } else
+ if (args==3) { /* No digi */
+ if (strcmp(addr,neigh)==0)
+ printf("%-6s %-9s",port,callsign);
+ }
+ }
+ fclose(fp);
+}
+
+void nodes(int s, int argc, char *argv[])
+{
+ struct rose_route_struct rs_node;
+ char *dev;
+ char *mask;
+ char nodeaddr[11];
+ int i, n;
+
+ FILE *fn;
+ char address[12], rmask[5], neigh1[10], neigh2[10], neigh3[10];
+ char buff[80];
+ int args;
+
+ if (argc < 3) {
+ fprintf(stderr, nodes_usage);
+ exit(1);
+ }
+
+ if (ax25_config_load_ports() == 0) {
+ fprintf(stderr, "rsparms: nodes: no AX.25 ports configured\n");
+ exit(1);
+ }
+
+ if (argv[2][0] != 'a' && argv[2][0] != 'd' && argv[2][0] != 'l') {
+ fprintf(stderr, "rsparms: nodes: invalid operation %s\n", argv[2]);
+ close(s);
+ exit(1);
+ }
+
+ if (argv[2][0] == 'l') {
+ if ((fn=fopen(PROC_RS_NODES_FILE,"r"))==NULL) {
+ fprintf(stderr,"rsparms: Couldn't open %s file\n",PROC_RS_NODES_FILE);
+ exit(1);
+ }
+
+ while(fgets(buff,80,fn)) {
+ args=sscanf(buff,"%10s %4s %*s %9s %9s %9s",address, rmask, neigh1, neigh2, neigh3);
+ if (strcmp(address,"address")==0)
+ continue;
+
+ if (args>2) {
+ printf("%10s/%4s -> ",address,rmask);
+ printnb(neigh1);
+ putchar('\n');
+ }
+ if (args>3) {
+ printf("%15s -> ","");
+ printnb(neigh2);
+ putchar('\n');
+ }
+ if (args>4) {
+ printf("%15s -> ","");
+ printnb(neigh3);
+ putchar('\n');
+ }
+ }
+ exit(0);
+ }
+
+ if (argc < 6) {
+ fprintf(stderr, nodes_usage);
+ exit(1);
+ }
+
+ if ((mask = strchr(argv[3], '/')) != NULL) {
+ *mask= (char)NULL;
+ mask++;
+
+ if (sscanf(mask, "%hd", &rs_node.mask) != 1) {
+ fprintf(stderr, "rsparms: nodes: no mask supplied!\n");
+ close(s);
+ exit(1);
+ }
+
+ if (rs_node.mask > 10) {
+ fprintf(stderr, "rsparms: nodes: invalid mask size: %s\n", mask);;
+ close(s);
+ exit(1);
+ }
+ } else {
+ rs_node.mask = 10;
+ }
+
+ /* Make all non significant digits equal to zero */
+ strcpy(nodeaddr, argv[3]);
+
+ for (i = rs_node.mask; i < 10; i++)
+ nodeaddr[i] = '0';
+
+ nodeaddr[i] = '\0';
+
+ if (rose_aton(nodeaddr, rs_node.address.rose_addr) != 0) {
+ fprintf(stderr, "rsparms: nodes: invalid address %s\n", nodeaddr);
+ close(s);
+ exit(1);
+ }
+
+ if ((dev = ax25_config_get_dev(argv[4])) == NULL) {
+ fprintf(stderr, "rsparms: nodes: invalid port name - %s\n", argv[4]);
+ close(s);
+ exit(1);
+ }
+
+ strcpy(rs_node.device, dev);
+
+ if (ax25_aton_entry(argv[5], rs_node.neighbour.ax25_call) != 0) {
+ fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[5]);
+ close(s);
+ exit(1);
+ }
+
+ for (i = 6, n = 0; i < argc && n < AX25_MAX_DIGIS; i++, n++) {
+ if (ax25_aton_entry(argv[i], rs_node.digipeaters[n].ax25_call) != 0) {
+ fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[i]);
+ close(s);
+ exit(1);
+ }
+ }
+
+ rs_node.ndigis = n;
+
+ if (argv[2][0] == 'a') {
+ if (ioctl(s, SIOCADDRT, &rs_node) == -1) {
+ perror("rsparms: SIOCADDRT");
+ close(s);
+ exit(1);
+ }
+ } else {
+ if (ioctl(s, SIOCDELRT, &rs_node) == -1) {
+ perror("rsparms: SIOCDELRT");
+ close(s);
+ exit(1);
+ }
+ }
+}
+
+
+
+
+int main(int argc, char *argv[])
+{
+ ax25_address rose_call;
+ int s = 0;
+
+ if (argc == 1) {
+ fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n");
+ return 1;
+ }
+
+ if (strncmp(argv[1], "-v", 2) == 0) {
+ printf("rsparms: %s\n", VERSION);
+ return 0;
+ }
+
+ if (strncmp(argv[1], "-c", 2) == 0) {
+ if (argc < 3) {
+ fprintf(stderr, "usage: rsparms -call <callsign>|none\n");
+ return 1;
+ }
+
+ if (strcmp(argv[2], "none") != 0) {
+ if (ax25_aton_entry(argv[2], rose_call.ax25_call) == -1) {
+ fprintf(stderr, "rsparms: invalid callsign %s\n", argv[2]);
+ return 1;
+ }
+ } else {
+ rose_call = null_ax25_address;
+ }
+
+ if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
+ perror("rsparms: socket");
+ return 1;
+ }
+
+ if (ioctl(s, SIOCRSL2CALL, &rose_call) == -1) {
+ perror("rsparms: ioctl");
+ close(s);
+ return 1;
+ }
+
+ close(s);
+
+ return 0;
+ }
+
+ if (strncmp(argv[1], "-n", 2) == 0) {
+
+ if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
+ perror("rsparms: socket");
+ return 1;
+ }
+ nodes(s, argc, argv);
+ close(s);
+ return 0;
+ }
+
+ fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n");
+
+ close(s);
+
+ return 1;
+}
diff --git a/rose/rsports b/rose/rsports
new file mode 100644
index 0000000..8be51a0
--- /dev/null
+++ b/rose/rsports
@@ -0,0 +1,7 @@
+# /etc/ax25/rsports
+#
+# The format of this file is:
+#
+# name address description
+#
+rose 2080192203 Rose port
diff --git a/rose/rsports.5 b/rose/rsports.5
new file mode 100644
index 0000000..44ce54e
--- /dev/null
+++ b/rose/rsports.5
@@ -0,0 +1,52 @@
+.TH RSPORTS 5 "27 August 1996" Linux "Linux Programmer's Manual"
+.SH NAME
+rsports \- Rose port configuration file.
+.SH DESCRIPTION
+.LP
+.B Rsports
+is an ASCII file that contains information about each of the Rose
+ports that are to be used. When dealing with a Rose 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 rsports,
+which has the same name. The information on each line contains
+enough information to bind the command to a particular Rose
+interface, this binding is done by matching the address on the line in
+.B rsports
+with the address of the port set by
+.B ifconfig
+or
+.B rsattach.
+.LP
+The
+.B rsports
+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 address description
+.RE
+.sp
+The field descriptions are:
+.sp
+.RS
+.TP 14
+.B name
+this is the unique Rose port identifier.
+.TP 14
+.B address
+the address of the Rose interface to bind to.
+.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/rsports
+.SH "SEE ALSO"
+.BR call (1),
+.BR rose (4),
+.BR ifconfig (8),
+.BR rsparms (8).
diff --git a/rose/rsuplnk.8 b/rose/rsuplnk.8
new file mode 100644
index 0000000..b9a65f1
--- /dev/null
+++ b/rose/rsuplnk.8
@@ -0,0 +1,63 @@
+.TH RSUPLNK 8 "29 April 1997" Linux "Linux Programmer's Manual"
+.SH NAME
+rsuplnk \- User entry into the ROSE network.
+.SH SYNOPSIS
+.B rsuplnk [-q] <port>
+.SH DESCRIPTION
+.LP
+The
+.B rsuplnk
+program allows a user to gain entry into the ROSE network using the standard
+pseudo-digipeating method. Recent Linux kernels are aware of this form
+of operation and the
+.B ax25d
+program can listen for such connections. The normal mode of operation of a
+ROSE switch is to have one ROSE address (ie port) per physical AX.25 port.
+Therefore ROSE users coming in on a given AX.25 port will appear as if they
+come from the associated ROSE port. This is the reason for the need for a
+ROSE port as an argument.
+.LP
+To use
+.B rsuplnk
+you need an entry in
+.B ax25d.conf
+to listen for incoming connections. In the example below, I will be
+listening for ROSE connections on my AX.25 port 144 using the callsign
+KE4GAJ-10 and the ROSE port associated with the AX.25 port is rs144.
+.LP
+#
+.br
+[KE4GAJ-10* VIA 144]
+.br
+NOCALL * * * * * * L
+.br
+default * * * * * * - root /usr/sbin/rsuplnk rsuplnk rs144
+.br
+#
+.LP
+There would typically be one
+.B rsuplnk
+per user access AX.25 port. The associated program for exiting a ROSE
+network is
+.B rsdwnlnk.
+.LP
+All errors generated by
+.B rsuplnk
+are written to the system debug log file.
+.SH OPTIONS
+.TP 8
+.BI \-q
+Supresses the messages generated by
+.B rsuplnk
+when making the connection.
+.SH FILES
+.br
+/etc/ax25/rsports
+.SH "SEE ALSO"
+.BR rose (4),
+.BR ax25d.conf (5),
+.BR ax25d (8),
+.BR rsdwnlnk (8),
+.BR rose_call (8).
+.SH AUTHOR
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
diff --git a/rose/rsuplnk.c b/rose/rsuplnk.c
new file mode 100644
index 0000000..a024e20
--- /dev/null
+++ b/rose/rsuplnk.c
@@ -0,0 +1,288 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <syslog.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/rsconfig.h>
+
+#include <config.h>
+
+void alarm_handler(int sig)
+{
+}
+
+int main(int argc, char **argv)
+{
+ unsigned char buffer[512], *addr, *p;
+ char rose_address[11];
+ fd_set read_fd;
+ int n, s, dnicindex = -1, addrindex = -1;
+ int addrlen, yes = 1, verbose = 1;
+ struct sockaddr_rose rosebind, roseconnect;
+ struct full_sockaddr_ax25 ax25sock, ax25peer;
+
+ openlog("rsuplnk", LOG_PID, LOG_DAEMON);
+
+ /*
+ * Arguments should be "rsuplnk [-q] roseport"
+ */
+ if (argc > 2 && strcmp(argv[1], "-q") == 0) {
+ verbose = 0;
+ --argc;
+ ++argv;
+ }
+
+ if (argc != 2) {
+ syslog(LOG_ERR, "invalid number of parameters\n");
+ closelog();
+ return 1;
+ }
+
+ if (rs_config_load_ports() == 0) {
+ syslog(LOG_ERR, "problem with rsports file\n");
+ closelog();
+ return 1;
+ }
+
+ addrlen = sizeof(struct full_sockaddr_ax25);
+
+ if (getsockname(STDIN_FILENO, (struct sockaddr *)&ax25sock, &addrlen) == -1) {
+ syslog(LOG_ERR, "cannot getsockname, %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+
+ addrlen = sizeof(struct full_sockaddr_ax25);
+
+ if (getpeername(STDIN_FILENO, (struct sockaddr *)&ax25peer, &addrlen) == -1) {
+ syslog(LOG_ERR, "cannot getpeername, %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+#ifdef HAVE_AX25_PIDINCL
+ if (setsockopt(STDIN_FILENO, SOL_AX25, AX25_PIDINCL, &yes, sizeof(yes)) == -1) {
+ syslog(LOG_ERR, "cannot setsockopt(AX25_PIDINCL) - %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+#endif /* HAVE_AX25_PIDINCL */
+ roseconnect.srose_family = rosebind.srose_family = AF_ROSE;
+ roseconnect.srose_ndigis = rosebind.srose_ndigis = 0;
+ addrlen = sizeof(struct sockaddr_rose);
+
+ if ((addr = rs_config_get_addr(argv[1])) == NULL) {
+ syslog(LOG_ERR, "invalid Rose port name - %s\n", argv[1]);
+ closelog();
+ return 1;
+ }
+
+ if (rose_aton(addr, rosebind.srose_addr.rose_addr) == -1) {
+ syslog(LOG_ERR, "invalid ROSE port address - %s\n", argv[1]);
+ closelog();
+ return 1;
+ }
+
+ /*
+ * Copy our DNIC in as default.
+ */
+ memset(rose_address, 0x00, 11);
+ memcpy(rose_address, addr, 4);
+
+ for (n = 0; n < ax25peer.fsa_ax25.sax25_ndigis; n++) {
+ addr = ax25_ntoa(&ax25peer.fsa_digipeater[n]);
+
+ if (strspn(addr, "0123456789-") == strlen(addr)) {
+ if ((p = strchr(addr, '-')) != NULL)
+ *p = '\0';
+ switch (strlen(addr)) {
+ case 4:
+ memcpy(rose_address + 0, addr, 4);
+ dnicindex = n;
+ break;
+ case 6:
+ memcpy(rose_address + 4, addr, 6);
+ addrindex = n;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /*
+ * The user didn't give an address.
+ */
+ if (addrindex == -1) {
+ strcpy(buffer, "*** No ROSE address given\r");
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+ sleep(20);
+ closelog();
+ return 1;
+ }
+
+ if (rose_aton(rose_address, roseconnect.srose_addr.rose_addr) == -1) {
+ syslog(LOG_ERR, "invalid Rose address - %s\n", argv[4]);
+ closelog();
+ return 1;
+ }
+
+ rosebind.srose_call = ax25peer.fsa_ax25.sax25_call;
+
+ roseconnect.srose_call = ax25sock.fsa_ax25.sax25_call;
+
+ /*
+ * A far end digipeater was specified.
+ */
+ if (addrindex > 0) {
+ roseconnect.srose_ndigis = 1;
+ roseconnect.srose_digi = ax25peer.fsa_digipeater[addrindex - 1];
+ }
+
+ /*
+ * Check for a local digipeater.
+ */
+ if (dnicindex != -1) {
+ if (ax25peer.fsa_ax25.sax25_ndigis - dnicindex > 2) {
+ rosebind.srose_ndigis = 1;
+ rosebind.srose_digi = ax25peer.fsa_digipeater[dnicindex + 2];
+ }
+ } else {
+ if (ax25peer.fsa_ax25.sax25_ndigis - addrindex > 2) {
+ rosebind.srose_ndigis = 1;
+ rosebind.srose_digi = ax25peer.fsa_digipeater[addrindex + 2];
+ }
+ }
+
+ /*
+ * Open the socket into the kernel.
+ */
+ if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "cannot open ROSE socket, %s\n", strerror(errno));
+ closelog();
+ return 1;
+ }
+
+ /*
+ * Set our AX.25 callsign and Rose address accordingly.
+ */
+ if (bind(s, (struct sockaddr *)&rosebind, addrlen) != 0) {
+ syslog(LOG_ERR, "cannot bind ROSE socket, %s\n", strerror(errno));
+ closelog();
+ close(s);
+ return 1;
+ }
+
+ if (setsockopt(s, SOL_ROSE, ROSE_QBITINCL, &yes, sizeof(yes)) == -1) {
+ syslog(LOG_ERR, "cannot setsockopt(ROSE_QBITINCL) - %s\n", strerror(errno));
+ closelog();
+ close(s);
+ return 1;
+ }
+
+ if (verbose) {
+ strcpy(buffer, "*** Connection in progress\r");
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+ }
+
+ /*
+ * If no response in 5 minutes, go away.
+ */
+ alarm(300);
+
+ signal(SIGALRM, alarm_handler);
+
+ /*
+ * Lets try and connect to the far end.
+ */
+ if (connect(s, (struct sockaddr *)&roseconnect, addrlen) != 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ strcpy(buffer, "*** Disconnected - 0100 - Number Busy\r");
+ break;
+ case ENETUNREACH:
+ strcpy(buffer, "*** Disconnected - 0D00 - Not Obtainable\r");
+ break;
+ case EINTR:
+ strcpy(buffer, "*** Disconnected - 3900 - Ship Absent\r");
+ break;
+ default:
+ sprintf(buffer, "*** Disconnected - %d - %s\r", errno, strerror(errno));
+ break;
+ }
+
+ close(s);
+
+ if (verbose) {
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+ sleep(20);
+ }
+
+ return 0;
+ }
+
+ /*
+ * We got there.
+ */
+ alarm(0);
+
+ if (verbose) {
+ strcpy(buffer, "*** Connected\r");
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+ }
+
+ /*
+ * Loop until one end of the connection goes away.
+ */
+ for (;;) {
+ FD_ZERO(&read_fd);
+ FD_SET(STDIN_FILENO, &read_fd);
+ FD_SET(s, &read_fd);
+
+ select(s + 1, &read_fd, NULL, NULL, NULL);
+
+ if (FD_ISSET(s, &read_fd)) {
+ if ((n = read(s, buffer, 512)) == -1) {
+ strcpy(buffer, "\r*** Disconnected - 0000 - DTE Originated\r");
+ write(STDOUT_FILENO, buffer, strlen(buffer));
+ break;
+ }
+ if (buffer[0] == 0) { /* Q Bit not set */
+ buffer[0] = 0xF0;
+ write(STDOUT_FILENO, buffer, n);
+ } else {
+ /* Lose the leading 0x7F */
+ write(STDOUT_FILENO, buffer + 2, n - 2);
+ }
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &read_fd)) {
+ if ((n = read(STDIN_FILENO, buffer + 2, 512)) == -1) {
+ close(s);
+ break;
+ }
+ if (buffer[2] == 0xF0) {
+ buffer[2] = 0;
+ write(s, buffer + 2, n);
+ } else {
+ buffer[0] = 1; /* Set Q bit on */
+ buffer[1] = 0x7F; /* PID Escape */
+ write(s, buffer, n + 2);
+ }
+ }
+ }
+
+ closelog();
+
+ return 0;
+}