summaryrefslogtreecommitdiffstats
path: root/6pack
diff options
context:
space:
mode:
authorThomas Osterried <thomas@osterried.de>2005-12-10 16:17:28 +0000
committerThomas Osterried <thomas@osterried.de>2005-12-10 16:17:28 +0000
commitcbc787a43d78bec5b22038d5c3d124820fc53aaa (patch)
tree48ad671c8c286a1513425cfa3cb311cb4c14cfcf /6pack
parentf4d3f0dc920f69aa903f91ae0ef2fb14b9a5195b (diff)
support for 6pack tnc rings (patch found at sf.net)
from Iñaki Arenaza EB2EBU <iarenaza@escomposlinux.org>
Diffstat (limited to '6pack')
-rw-r--r--6pack/Makefile.am20
-rw-r--r--6pack/Makefile.in387
-rw-r--r--6pack/m6pack.854
-rw-r--r--6pack/m6pack.c666
4 files changed, 1127 insertions, 0 deletions
diff --git a/6pack/Makefile.am b/6pack/Makefile.am
new file mode 100644
index 0000000..e9673a1
--- /dev/null
+++ b/6pack/Makefile.am
@@ -0,0 +1,20 @@
+
+installconf:
+
+sbin_PROGRAMS = m6pack
+
+LDADD= $(AX25_LIB)
+
+man_MANS = m6pack.8
+
+EXTRA_DIST = $(man_MANS)
+
+INCLUDES = -DAX25_SYSCONFDIR=\""$(AX25_SYSCONFDIR)"\" \
+ -DAX25_LOCALSTATEDIR=\""$(AX25_LOCALSTATEDIR)"\"
+
+AX25_SYSCONFDIR=${sysconfdir}/ax25/
+AX25_LOCALSTATEDIR=${localstatedir}/ax25/
+
+install-exec-local:
+ (cd $(DESTDIR)$(sbindir))
+
diff --git a/6pack/Makefile.in b/6pack/Makefile.in
new file mode 100644
index 0000000..17e26ed
--- /dev/null
+++ b/6pack/Makefile.in
@@ -0,0 +1,387 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AWK = @AWK@
+AX25IO_LIB = @AX25IO_LIB@
+AX25_LIB = @AX25_LIB@
+CC = @CC@
+CXX = @CXX@
+FLTK_LIB = @FLTK_LIB@
+HAVE_LIB = @HAVE_LIB@
+LIB = @LIB@
+LTLIB = @LTLIB@
+MAKEINFO = @MAKEINFO@
+NCURSES_LIB = @NCURSES_LIB@
+PACKAGE = @PACKAGE@
+UTIL_LIB = @UTIL_LIB@
+VERSION = @VERSION@
+Z_LIB = @Z_LIB@
+
+sbin_PROGRAMS = m6pack
+
+LDADD = $(AX25_LIB)
+
+man_MANS = m6pack.8
+
+EXTRA_DIST = $(man_MANS)
+
+INCLUDES = -DAX25_SYSCONFDIR=\""$(AX25_SYSCONFDIR)"\" -DAX25_LOCALSTATEDIR=\""$(AX25_LOCALSTATEDIR)"\"
+
+
+AX25_SYSCONFDIR = ${sysconfdir}/ax25/
+AX25_LOCALSTATEDIR = ${localstatedir}/ax25/
+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@
+m6pack_SOURCES = m6pack.c
+m6pack_OBJECTS = m6pack.o
+m6pack_LDADD = $(LDADD)
+m6pack_DEPENDENCIES =
+m6pack_LDFLAGS =
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+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
+DEP_FILES = .deps/m6pack.P
+SOURCES = m6pack.c
+OBJECTS = m6pack.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 6pack/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ 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
+
+.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:
+
+m6pack: $(m6pack_OBJECTS) $(m6pack_DEPENDENCIES)
+ @rm -f m6pack
+ $(LINK) $(m6pack_LDFLAGS) $(m6pack_OBJECTS) $(m6pack_LDADD) $(LIBS)
+
+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-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) 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 -o $$here/TAGS $(ETAGS_ARGS) $$tags $$unique $(LISP))
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = 6pack
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu 6pack/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+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-local
+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)/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-depend mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-depend \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \
+ distclean-depend distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-sbinPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-depend 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-man8 uninstall-man8 \
+install-man uninstall-man tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir mostlyclean-depend \
+distclean-depend clean-depend maintainer-clean-depend info-am info \
+dvi-am dvi check check-am installcheck-am installcheck \
+install-exec-local 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:
+
+install-exec-local:
+ (cd $(DESTDIR)$(sbindir))
+
+# 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/6pack/m6pack.8 b/6pack/m6pack.8
new file mode 100644
index 0000000..831942c
--- /dev/null
+++ b/6pack/m6pack.8
@@ -0,0 +1,54 @@
+.TH M6PACK 8 "28 April 2002" Linux "Linux System Managers Manual"
+.SH NAME
+m6pack \- Attach multiples 6PACK interfaces
+.SH SYNOPSIS
+.B m6pack [-l] [-s speed] [-v] ttyinterface pty1 pty2...
+.SH DESCRIPTION
+.LP
+.B m6pack
+allows multiple 6PACK TNCs sharing the same serial port to be
+used with the Linux AX.25 kernel software. The AX.25 softare has no support
+for multiple TNCs sharing the same serial line. The
+different ports are addressed by encoding the port number in the control
+byte of every 6pack frame.
+.B m6pack
+watches a serial port, and routes 6pack frames to/from the pseudo ttys. The
+other side of the pseudo ttys are then attached with
+.B spattach
+as normal.
+.sp 1
+Statistics about the operation of
+.B m6pack
+may be obtained by sending the SIGUSR1 signal to the running program. On
+reception of such a signal
+.B m6pack
+will print a set of statistics to the system log if logging has been
+enabled.
+.sp 1
+Although mention is made of using pseudo ttys as the last arguments,
+these devices may be normal serial ports. However
+.B m6pack
+provides no way in which to set their speed, the speed must therefore be set
+by some other method.
+.SH OPTIONS
+.TP 10
+.BI \-l
+Enables system logging, the default is off.
+.TP 10
+.BI "\-s speed"
+Set the speed of the serial port.
+.TP 10
+.BI \-v
+Display the version.
+.SH "SEE ALSO"
+.BR spattach (8),
+.BR ifconfig (8),
+.BR kill (1).
+.SH AUTHORS
+Iñaki Arenaza EB2EBU <iarenaza@escomposlinux.org>, based in the work by:
+.br
+Tomi Manninen OH2BNS <tpmannin@cc.hut.fi>
+.br
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
+.br
+Kevin Uhlir N0BEL <kevinu@flochart.com>
diff --git a/6pack/m6pack.c b/6pack/m6pack.c
new file mode 100644
index 0000000..65f85c4
--- /dev/null
+++ b/6pack/m6pack.c
@@ -0,0 +1,666 @@
+/* Hey Emacs! this is -*- linux-c -*-
+ * from /usr/src/linux/Documentation/CodingStyle
+ *
+ * m6pack.c
+ *
+ * Fake out AX.25 code into supporting 6pack TNC rings by routing serial
+ * port data to/from pseudo ttys.
+ *
+ * @(#)m6pack.c $Revision: 1.1 $ $Date: 2005/12/10 16:17:28 $
+ *
+ * Author(s):
+ *
+ * Iñaki Arenaza (EB2EBU) <iarenaza@escomposlinux.org>
+ *
+ * History:
+ *
+ * $Log: m6pack.c,v $
+ * Revision 1.1 2005/12/10 16:17:28 dl9sau
+ * support for 6pack tnc rings (patch found at sf.net)
+ * from Iñaki Arenaza EB2EBU <iarenaza@escomposlinux.org>
+ *
+ * Revision 0.9 2002/04/28 15:05:39 hermes-team
+ * Minor fixes to make it part of ax25-tools-0.0.8
+ *
+ * Revision 0.7 1999/04/25 11:03:51 hermes-team
+ * Minor cosmetic changes.
+ *
+ * Revision 0.6 1999/04/25 10:30:51 hermes-team
+ * TTY unlocking was missing from SIGTERM handler. Thanks to Tommi Manninen
+ * for pointing it out.
+ *
+ * Revision 0.5 1999/04/07 09:16:06 hermes-team
+ * First public beta release. It _seems_ to work with two TNC's in a ring
+ * (I only have two TNC's to test :-(
+ *
+ * Revision 0.4 1999/04/06 14:35:56 hermes-team
+ * Removed the code that checked that trailing SEOF's address was equal to
+ * leading SEOF's address (it seems this hasn't to be so, but it wasn't very
+ * clear in DG2FEF & HB9JNX's paper)
+ *
+ * Revision 0.3 1999/01/31 23:02:09 hermes-team
+ * Modified code that calls write(2) in sixpack_tx to handle big data blocks.
+ *
+ * Revision 0.2 1999/01/31 15:56:51 hermes-team
+ * Initial Release. This is still alpha software.
+ *
+ *********************************************************************
+ *
+ * Quite a lot of stuff "stolen" from mkiss.c, written by
+ *
+ * Kevin Uhlir
+ * Ron Curry
+ * Jonathan Naylor
+ * Tomi Manninen
+ *
+ * Copyright (C) 1999 Iñaki Arenaza
+ * mkiss.c was GPLed, so I guess this one is GPLed too ;-)
+ *
+ *********************************************************************
+ *
+ * REMARK:
+ *
+ * See document '6pack.ps' by Matthias Welwarsky (DG2FEF), translated
+ * by Thomas Sailer (HB9JNX) found in ax25-doc-1.0.tgz for details about
+ * 6pack protocol specifications.
+ *
+ *********************************************************************
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#include <netax25/ttyutils.h>
+#include <netax25/daemon.h>
+
+#include <config.h>
+
+static char *version ="$Id: m6pack.c,v 1.1 2005/12/10 16:17:28 dl9sau Exp $";
+
+typedef unsigned char __u8;
+typedef enum {data, command} frame_t;
+
+#define SIXP_MAX_ADDR ((__u8) 8)
+#define SIZE 4096
+#define MAX_PTYS SIXP_MAX_ADDR /* Max number of TNCs in a 6PACK ring */
+
+/*
+ * Keep these off the stack.
+ */
+static __u8 ibuf[SIZE]; /* buffer for input operations */
+static __u8 obuf[SIZE]; /* buffer for sixpack_tx() */
+
+static int invalid_ports = 0;
+
+static char *usage_string = "usage: m6pack [-l] [-s speed] [-v] "
+ "ttyinterface pty ...\n";
+
+static int dump_report = FALSE;
+static int logging = FALSE;
+
+static struct iface *pty[MAX_PTYS];
+static struct iface *tty;
+static int numptys;
+
+struct iface
+{
+ char *name; /* Interface name (/dev/???) */
+ int fd; /* File descriptor */
+ int pty_id; /* 6pack address asigned to pty */
+ __u8 seof; /* leading SEOF of this frame */
+ __u8 databuf[SIZE]; /* TX buffer (data frames) */
+ __u8 cmdbuf[1]; /* TX buffer (command frames) */
+ __u8 *optr; /* Next byte to transmit */
+ unsigned int sixp_cnt; /* 6pack-coded octets count */
+ unsigned int decod_cnt; /* 6pack-decoded octets cont */
+ unsigned int errors; /* 6PACK frame error count */
+ unsigned int rxpackets; /* RX frames count */
+ unsigned int txpackets; /* TX frames count */
+ unsigned long rxbytes; /* RX bytes count */
+ unsigned long txbytes; /* TX bytes count */
+};
+
+#define PTY_ID_TTY (-1)
+
+/* 6PACK "TNC Address" commands are special in that the address they
+ * carry is not the address of the destination TNC but the initial
+ * address for the firt TNC in the ring (when sent PC->TNC Ring), or
+ * the last TNC address+1 (when received TNC ring -> PC). So we can't
+ * use the address in the command to select a pty to pass the
+ * command, and we have to keep track of what ptys have sent "TNC
+ * Address" commands to sent them back the response (until we modify
+ * the kernel 6pack driver to support multiple TNC's (i.e., network
+ * devices) on one serial port). We deliver the responses with a FIFO
+ * policy.
+ */
+static int cmd_addr_fifo[SIXP_MAX_ADDR];
+static int head; /* We retrieve from head position */
+static int tail; /* We insert at tail position */
+
+/* Masks to tell apart 6pack command and data frames
+ */
+#define SIXP_IS_DATA(x) ((((__u8)(x)) & (__u8)0xC0) == (__u8)0)
+#define SIXP_IS_CMD(x) !(SIXP_IS_DATA(x))
+
+/* Masks to split commands in opcode and TNC address
+ */
+#define SIXP_ADDR_MASK ((__u8) (SIXP_MAX_ADDR-1))
+#define SIXP_CMD_MASK ((__u8) ~SIXP_ADDR_MASK)
+#define SIXP_CMD(x) (((__u8)x) & SIXP_CMD_MASK)
+#define SIXP_ADDR(x) (((__u8)x) & SIXP_ADDR_MASK)
+
+/* Macro to build a 6pack TNC command from opcode and TNC address
+ */
+#define SIXP_MAKE_CMD(opcode,addr) (((__u8)opcode) | ((__u8)addr))
+
+/* 6pack protocol commands (relevant bits only)
+ */
+#define SIXP_CMD_SEOF ((__u8) 0x40) /* start/end of 6pack frame */
+#define SIXP_CMD_TX_ORUN ((__u8) 0x48) /* transmit overrun */
+#define SIXP_CMD_RX_ORUN ((__u8) 0x50) /* receive overrun */
+#define SIXP_CMD_RX_BUF_OVL ((__u8) 0x58) /* receive buffer overflow */
+#define SIXP_CMD_LED ((__u8) 0x60) /* set LED status */
+#define SIXP_CMD_TX_1 ((__u8) 0xA0) /* TX counter + 1 */
+#define SIXP_CMD_RX_1 ((__u8) 0x90) /* RX counter + 1 */
+#define SIXP_CMD_DCD ((__u8) 0x88) /* DCD state */
+#define SIXP_CMD_CAL ((__u8) 0xE0) /* send calibration pattern */
+#define SIXP_CMD_ADDR ((__u8) 0xE8) /* set TNC address */
+
+/* Valid checksum of a 6pack frame
+ */
+#define SIXP_CHKSUM ((__u8) 0xFF)
+
+static int sixpack_rx(struct iface *ifp, __u8 c, __u8 *tnc_addr, frame_t *type)
+{
+ int i, len;
+ __u8 checksum;
+
+ /* Is it a data octect?
+ */
+ if (SIXP_IS_DATA(c)) {
+ /* Decode the 6PACK octect and store the resultant
+ * bits in the output buffer.
+ */
+ switch (ifp->sixp_cnt % 4) {
+ case 0:
+ *ifp->optr = (c & 0x3F);
+ break;
+ case 1:
+ *ifp->optr++ |= (c & 0x30) << 2;
+ *ifp->optr = (c & 0x0F);
+ break;
+ case 2:
+ *ifp->optr++ |= (c & 0x3C) << 2;
+ *ifp->optr = (c & 0x03);
+ break;
+ default:
+ *ifp->optr++ |= (c & 0x3F) << 2;
+ }
+ ifp->sixp_cnt++;
+ return 0;
+ }
+
+ /* Nope, it's a command octect. See which kind of command.
+ * Anything but a SEOF command is a one-octect command, so
+ * process it immediately and return.
+ */
+ if (SIXP_CMD(c) != SIXP_CMD_SEOF) {
+ if (SIXP_CMD(c) == SIXP_CMD_ADDR) {
+ /* 6PACK "TNC Address" commans are
+ * "special". The address field must be
+ * rewritten.
+ */
+ if (PTY_ID_TTY == ifp->pty_id) {
+ /* TNC Ring -> pty
+ * Dequeue a TNC Address request.
+ */
+ *ifp->cmdbuf = SIXP_MAKE_CMD(SIXP_CMD(c),1);
+ *tnc_addr = cmd_addr_fifo[head];
+ head = (head + 1) % SIXP_MAX_ADDR;
+ }
+ else {
+ /* pty -> TNC Ring
+ * Enqueue a TNC Address request.
+ */
+ *ifp->cmdbuf = SIXP_MAKE_CMD(SIXP_CMD(c), 0);
+ *tnc_addr = 0;
+ cmd_addr_fifo[tail] = ifp->pty_id;
+ tail = (tail + 1) % SIXP_MAX_ADDR;
+ }
+ }
+ else {
+ /* We need a separate buffer here for 6PACK commands
+ * as the protocol allows the transmission of command
+ * frames in the middle of data frames. Don't touch
+ * anything else! A data frame may be "en route".
+ */
+ *ifp->cmdbuf = SIXP_CMD(c);
+ *tnc_addr = SIXP_ADDR(c);
+ }
+ /* Update statistics and return.
+ */
+ ifp->rxpackets++;
+ ifp->rxbytes++;
+ *type = command;
+ return 1;
+ }
+
+ /* We're dealing with a SEOF command.
+ */
+ len = ifp->optr - ifp->databuf;
+ if (len > 0) {
+ if (len < 3) {
+ /* Data frames have at least 3 octets:
+ * TxDelay, Datum, CheckSum.
+ * Signal error and reset state.
+ */
+ goto error_reset_state;
+ }
+
+ /* Now that we've decoded 6PACK octects,
+ * check the checksum of the frame.
+ */
+ checksum = 0;
+ for (i = 0; i < len; i++) {
+ checksum += ifp->databuf[i];
+ }
+ /* Address of this frame must be taken from the
+ * leading SEOF.
+ */
+ *tnc_addr = SIXP_ADDR(ifp->seof);
+ checksum += *tnc_addr;
+
+ if (checksum != SIXP_CHKSUM) {
+ /* Signal error and reset state.
+ */
+ goto error_reset_state;
+ }
+
+ /* Now remove checksum from the frame (this makes
+ * sixpack_tx easier).
+ */
+ len--;/* Minus Checksum */
+
+ /* Finally update statistics and return all
+ * needed parameters
+ */
+ ifp->rxpackets++;
+ ifp->rxbytes += len;
+ *type = data;
+ }
+
+ ifp->optr = ifp->databuf;
+ ifp->seof = c;
+ ifp->sixp_cnt = 0;
+ ifp->decod_cnt = 0;
+ return len;
+
+ error_reset_state:
+ ifp->errors++;
+ ifp->optr = ifp->databuf;
+ ifp->sixp_cnt = 0;
+ ifp->decod_cnt = 0;
+ return 0;
+}
+
+static void sixpack_tx(int fd, __u8 tnc_addr, __u8 *ibuf, int len, frame_t type)
+{
+ __u8 *ptr = obuf;
+ __u8 checksum;
+ int count, written;
+
+ if (type == command) {
+ if (SIXP_CMD(*ibuf) == SIXP_CMD_ADDR) {
+ /* 6PACK "TNC Address" commans are
+ * "special". We must send them untouched here.
+ */
+ *ptr++ = *ibuf;
+ }
+ else {
+ /* Commands, except SEOF, are 1 byte long.
+ */
+ *ptr++ = SIXP_MAKE_CMD(SIXP_CMD(*ibuf), tnc_addr);
+ }
+ }
+ else {
+ *ptr++ = SIXP_MAKE_CMD(SIXP_CMD_SEOF, tnc_addr);
+ checksum = 0;
+ for (count = 0; count < len; count++) {
+ switch (count % 3) {
+ case 0:
+ *ptr++ = (ibuf[count] & 0x3F);
+ *ptr = (ibuf[count] & 0xC0) >> 2;
+ break;
+ case 1:
+ *ptr++ |= (ibuf[count] & 0x0F);
+ *ptr = (ibuf[count] & 0xF0) >> 2;
+ break;
+ default:
+ *ptr++ |= (ibuf[count] & 0x03);
+ *ptr++ = (ibuf[count] & 0xFC) >> 2;
+ break;
+ }
+ checksum += ibuf[count];
+ }
+
+ checksum += tnc_addr;
+ checksum = 0xFF - checksum;
+ switch (count % 3) {
+ case 0:
+ *ptr++ = (checksum & 0x3F);
+ *ptr++ = (checksum & 0xC0) >> 2;
+ break;
+ case 1:
+ *ptr++ |= (checksum & 0x0F);
+ *ptr++ = (checksum & 0xF0) >> 2;
+ break;
+ default:
+ *ptr++ |= (checksum & 0x03);
+ *ptr++ = (checksum & 0xFC) >> 2;
+ break;
+ }
+
+ /* Trailing SEOF doesn't carry TNC address
+ */
+ *ptr++ = SIXP_MAKE_CMD(SIXP_CMD_SEOF, 0);
+ }
+
+ count = ptr - obuf;
+ written = 0;
+ ptr = obuf;
+ while (count > 0) {
+ written = write (fd, ptr, count);
+ count -= written;
+ ptr += written;
+ }
+}
+
+static void sigterm_handler(int sig)
+{
+ int i;
+
+ if (logging) {
+ syslog(LOG_INFO, "terminating on SIGTERM\n");
+ closelog();
+ }
+
+ tty_unlock(tty->name);
+ for (i=0; i < numptys; i++) {
+ tty_unlock(pty[i]->name);
+ }
+
+ close(tty->fd);
+ free(tty);
+ for (i = 0; i < numptys; i++) {
+ close(pty[i]->fd);
+ free(pty[i]);
+ }
+
+ exit(0);
+}
+
+static void sigusr1_handler(int sig)
+{
+ signal(SIGUSR1, sigusr1_handler);
+ dump_report = TRUE;
+}
+
+static void report(struct iface *tty, struct iface **pty, int numptys)
+{
+ int i;
+ long t;
+
+ time(&t);
+ syslog(LOG_INFO, "version %s.", VERSION);
+ syslog(LOG_INFO, "Status report at %s", ctime(&t));
+ syslog(LOG_INFO, "ttyinterface is %s (fd=%d)", tty->name, tty->fd);
+ for (i = 0; i < numptys; i++)
+ syslog(LOG_INFO, "pty%d is %s (fd=%d)", i, pty[i]->name,
+ pty[i]->fd);
+ syslog(LOG_INFO, "Invalid ports: %d", invalid_ports);
+ syslog(LOG_INFO, "Interface TX frames TX bytes RX frames RX "
+ "bytes Errors");
+ syslog(LOG_INFO, "%-11s %-9u %-9lu %-9u %-9lu %u",
+ tty->name,
+ tty->txpackets, tty->txbytes,
+ tty->rxpackets, tty->rxbytes,
+ tty->errors);
+ for (i = 0; i < numptys; i++) {
+ syslog(LOG_INFO, "%-11s %-9u %-9lu %-9u %-9lu %u",
+ pty[i]->name,
+ pty[i]->txpackets, pty[i]->txbytes,
+ pty[i]->rxpackets, pty[i]->rxbytes,
+ pty[i]->errors);
+ }
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ __u8 *icp, tnc_addr;
+ int topfd;
+ fd_set readfd;
+ int retval, i, size, len;
+ int speed = -1;
+ frame_t type;
+
+ head = tail = 0;
+ while ((size = getopt(argc, argv, "ls:v")) != -1) {
+ switch (size) {
+ case 'l':
+ logging = TRUE;
+ break;
+ case 's':
+ speed = atoi(optarg);
+ break;
+ case 'v':
+ printf("m6pack: %s\n", VERSION);
+ return 1;
+ case ':':
+ case '?':
+ fprintf(stderr, usage_string);
+ return 1;
+ }
+ }
+
+ if ((argc - optind) < 2) {
+ fprintf(stderr, usage_string);
+ return 1;
+ }
+ if ((numptys = argc - optind - 1) > MAX_PTYS) {
+ fprintf(stderr, "m6pack: max %d pty interfaces allowed.\n",
+ MAX_PTYS);
+ return 1;
+ }
+
+ /*
+ * Check for lock files before opening any TTYs
+ */
+ if (tty_is_locked(argv[optind])) {
+ fprintf(stderr, "m6pack: tty %s is locked by another "
+ "process\n", argv[optind]);
+ return 1;
+ }
+ for (i = 0; i < numptys; i++) {
+ if (tty_is_locked(argv[optind + i + 1])) {
+ fprintf(stderr, "m6pack: tty %s is locked by "
+ "another process\n", argv[optind + i + 1]);
+ return 1;
+ }
+ }
+
+ /*
+ * Open and configure the tty interface. Open() is
+ * non-blocking so it won't block regardless of the modem
+ * status lines.
+ */
+ if ((tty = calloc(1, sizeof(struct iface))) == NULL) {
+ perror("m6pack: malloc");
+ return 1;
+ }
+
+ if ((tty->fd = open(argv[optind], O_RDWR | O_NDELAY)) == -1) {
+ perror("m6pack: open");
+ return 1;
+ }
+
+ tty->name = argv[optind];
+ if (speed != -1) tty_speed(tty->fd, speed);
+ tty_raw(tty->fd, FALSE);
+ tty->pty_id = PTY_ID_TTY;
+ tty->optr = tty->databuf;
+ topfd = tty->fd;
+ /*
+ * Make it block again...
+ */
+ fcntl(tty->fd, F_SETFL, 0);
+
+ /*
+ * Open and configure the pty interfaces
+ */
+ for (i = 0; i < numptys; i++) {
+ if ((pty[i] = calloc(1, sizeof(struct iface))) == NULL) {
+ perror("m6pack: malloc");
+ return 1;
+ }
+ if ((pty[i]->fd = open(argv[optind + i + 1], O_RDWR)) == -1) {
+ perror("m6pack: open");
+ return 1;
+ }
+ pty[i]->name = argv[optind + i + 1];
+ tty_raw(pty[i]->fd, FALSE);
+ pty[i]->pty_id = i;
+ pty[i]->optr = pty[i]->databuf;
+ topfd = (pty[i]->fd > topfd) ? pty[i]->fd : topfd;
+ }
+
+ /*
+ * Now all the ports are open, lock them.
+ */
+ tty_lock(argv[optind]);
+ for (i = 0; i < numptys; i++)
+ tty_lock(argv[optind + i + 1]);
+
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGUSR1, sigusr1_handler);
+ signal(SIGTERM, sigterm_handler);
+
+ if (!daemon_start(FALSE)) {
+ fprintf(stderr, "m6pack: cannot become a daemon\n");
+ return 1;
+ }
+
+ if (logging) {
+ openlog("m6pack", LOG_PID, LOG_DAEMON);
+ syslog(LOG_INFO, "starting");
+ }
+
+ /*
+ * Loop until an error occurs on a read.
+ */
+ while (TRUE) {
+ FD_ZERO(&readfd);
+ FD_SET(tty->fd, &readfd);
+ for (i = 0; i < numptys; i++)
+ FD_SET(pty[i]->fd, &readfd);
+
+ errno = 0;
+ retval = select(topfd + 1, &readfd, NULL, NULL, NULL);
+
+ if (retval == -1) {
+ if (dump_report) {
+ if (logging)
+ report(tty, pty, numptys);
+ dump_report = FALSE;
+ continue;
+ } else {
+ perror("m6pack: select");
+ continue;
+ }
+ }
+
+
+ /*
+ * A character has arrived on the ttyinterface.
+ */
+ if (FD_ISSET(tty->fd, &readfd)) {
+ if ((size = read(tty->fd, ibuf, SIZE)) < 0
+ && errno != EINTR) {
+ if (logging)
+ syslog(LOG_ERR, "tty->fd: %m");
+ break;
+ }
+
+ for (icp = ibuf; size > 0; size--, icp++) {
+ if ((len = sixpack_rx(tty,*icp,&tnc_addr,
+ &type)) != 0) {
+ if (tnc_addr <= numptys) {
+ sixpack_tx(pty[tnc_addr]->fd,
+ 0,
+ (type == data) ?
+ tty->databuf :
+ tty->cmdbuf,
+ len,
+ type);
+ pty[tnc_addr]->txpackets++;
+ pty[tnc_addr]->txbytes += len;
+ } else
+ invalid_ports++;
+ }
+ }
+ }
+
+ for (i = 0; i < numptys; i++) {
+ /*
+ * A character has arrived on pty[i].
+ */
+ if (FD_ISSET(pty[i]->fd, &readfd)) {
+ if ((size = read(pty[i]->fd, ibuf, SIZE)) < 0
+ && errno != EINTR) {
+ if (logging)
+ syslog(LOG_ERR,
+ "pty[%d]->fd: %m\n",i);
+ goto end;
+ }
+
+ for (icp = ibuf; size > 0; size--, icp++) {
+ if ((len = sixpack_rx(pty[i],
+ *icp,
+ &tnc_addr,
+ &type)) != 0) {
+ sixpack_tx(tty->fd, i,
+ (type == data) ?
+ pty[i]->databuf :
+ pty[i]->cmdbuf,
+ len, type);
+ tty->txpackets++;
+ tty->txbytes += len;
+ }
+ }
+ }
+ }
+ }
+
+ end:
+ if (logging)
+ closelog();
+
+ close(tty->fd);
+ free(tty);
+
+ for (i = 0; i < numptys; i++) {
+ close(pty[i]->fd);
+ free(pty[i]);
+ }
+ return 1;
+}