From cbc787a43d78bec5b22038d5c3d124820fc53aaa Mon Sep 17 00:00:00 2001 From: Thomas Osterried Date: Sat, 10 Dec 2005 16:17:28 +0000 Subject: =?UTF-8?q?=20=20=20=20=20=20=20=20support=20for=206pack=20tnc=20r?= =?UTF-8?q?ings=20(patch=20found=20at=20sf.net)=20=09from=20I=C3=B1aki=20A?= =?UTF-8?q?renaza=20EB2EBU=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 6pack/Makefile.am | 20 ++ 6pack/Makefile.in | 387 +++++++++++++++++++++++++++++++ 6pack/m6pack.8 | 54 +++++ 6pack/m6pack.c | 666 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 2 +- Makefile.in | 22 +- configure.in | 2 +- 7 files changed, 1143 insertions(+), 10 deletions(-) create mode 100644 6pack/Makefile.am create mode 100644 6pack/Makefile.in create mode 100644 6pack/m6pack.8 create mode 100644 6pack/m6pack.c 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 , based in the work by: +.br +Tomi Manninen OH2BNS +.br +Jonathan Naylor G4KLX +.br +Kevin Uhlir N0BEL 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) + * + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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; +} diff --git a/Makefile.am b/Makefile.am index c8797c7..c587c3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ installconf: @for app in $(SUBDIRS); do $(MAKE) -C $$app installconf; done -SUBDIRS = ax25 hdlcutil kiss netrom rose tcpip user_call yamdrv dmascc +SUBDIRS = ax25 hdlcutil kiss 6pack netrom rose tcpip user_call yamdrv dmascc EXTRA_DIST = pathnames.h diff --git a/Makefile.in b/Makefile.in index 42898f5..79d0a8e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ -# Makefile.in generated automatically by automake 1.4-p4 from Makefile.am +# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# 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. @@ -57,12 +57,17 @@ 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@ @@ -70,7 +75,7 @@ UTIL_LIB = @UTIL_LIB@ VERSION = @VERSION@ Z_LIB = @Z_LIB@ -SUBDIRS = ax25 hdlcutil kiss netrom rose tcpip user_call yamdrv dmascc +SUBDIRS = ax25 hdlcutil kiss 6pack netrom rose tcpip user_call yamdrv dmascc EXTRA_DIST = pathnames.h @@ -84,8 +89,9 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = DIST_COMMON = README ./stamp-h.in AUTHORS COPYING ChangeLog INSTALL \ -Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.h.in \ -configure configure.in install-sh missing mkinstalldirs +Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.guess \ +config.h.in config.sub configure configure.in install-sh missing \ +mkinstalldirs DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) @@ -104,7 +110,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) $(ACLOCAL_M4): configure.in cd $(srcdir) && $(ACLOCAL) -config.status: $(srcdir)/configure.in $(CONFIG_STATUS_DEPENDENCIES) +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) cd $(srcdir) && $(AUTOCONF) @@ -173,7 +179,7 @@ maintainer-clean-recursive: dot_seen=no; \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev="$$subdir $$rev"; \ - test "$$subdir" = "." && dot_seen=yes; \ + test "$$subdir" != "." || dot_seen=yes; \ done; \ test "$$dot_seen" = "no" && rev=". $$rev"; \ target=`echo $@ | sed s/-recursive//`; \ @@ -215,7 +221,7 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LI awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP)) mostlyclean-tags: diff --git a/configure.in b/configure.in index 0893ec8..9308d05 100644 --- a/configure.in +++ b/configure.in @@ -76,4 +76,4 @@ if test "x$GCC" = "xyes"; then fi fi -AC_OUTPUT(netrom/Makefile tcpip/Makefile ax25/Makefile Makefile rose/Makefile user_call/Makefile kiss/Makefile hdlcutil/Makefile hdlcutil/fl/Makefile yamdrv/Makefile dmascc/Makefile) +AC_OUTPUT(netrom/Makefile tcpip/Makefile ax25/Makefile Makefile rose/Makefile user_call/Makefile kiss/Makefile 6pack/Makefile hdlcutil/Makefile hdlcutil/fl/Makefile yamdrv/Makefile dmascc/Makefile) -- cgit v1.2.3