From 17287576555a5c46fa23549e2e5f073660dccb70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Apr 1999 09:51:03 +0200 Subject: Import ax25-tools 0.0.1 from tarball --- kiss/Makefile.am | 8 + kiss/Makefile.in | 367 +++++++++++++++++++++++++++++++ kiss/kissattach.c | 289 ++++++++++++++++++++++++ kiss/kissnetd.c | 257 ++++++++++++++++++++++ kiss/kissparms.c | 221 +++++++++++++++++++ kiss/mkiss.c | 512 +++++++++++++++++++++++++++++++++++++++++++ kiss/net2kiss.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2297 insertions(+) create mode 100644 kiss/Makefile.am create mode 100644 kiss/Makefile.in create mode 100644 kiss/kissattach.c create mode 100644 kiss/kissnetd.c create mode 100644 kiss/kissparms.c create mode 100644 kiss/mkiss.c create mode 100644 kiss/net2kiss.c (limited to 'kiss') diff --git a/kiss/Makefile.am b/kiss/Makefile.am new file mode 100644 index 0000000..7a130da --- /dev/null +++ b/kiss/Makefile.am @@ -0,0 +1,8 @@ + +installconf: + +sbin_PROGRAMS = kissattach kissnetd kissparms mkiss net2kiss + +man_MANS = kissattach.8 kissnetd.8 kissparms.8 mkiss.8 net2kiss.8 + + diff --git a/kiss/Makefile.in b/kiss/Makefile.in new file mode 100644 index 0000000..883ef04 --- /dev/null +++ b/kiss/Makefile.in @@ -0,0 +1,367 @@ +# 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@ + +sbin_PROGRAMS = kissattach kissnetd kissparms mkiss net2kiss + +man_MANS = kissattach.8 kissnetd.8 kissparms.8 mkiss.8 net2kiss.8 +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@ +kissattach_SOURCES = kissattach.c +kissattach_OBJECTS = kissattach.o +kissattach_LDADD = $(LDADD) +kissattach_DEPENDENCIES = +kissattach_LDFLAGS = +kissnetd_SOURCES = kissnetd.c +kissnetd_OBJECTS = kissnetd.o +kissnetd_LDADD = $(LDADD) +kissnetd_DEPENDENCIES = +kissnetd_LDFLAGS = +kissparms_SOURCES = kissparms.c +kissparms_OBJECTS = kissparms.o +kissparms_LDADD = $(LDADD) +kissparms_DEPENDENCIES = +kissparms_LDFLAGS = +mkiss_SOURCES = mkiss.c +mkiss_OBJECTS = mkiss.o +mkiss_LDADD = $(LDADD) +mkiss_DEPENDENCIES = +mkiss_LDFLAGS = +net2kiss_SOURCES = net2kiss.c +net2kiss_OBJECTS = net2kiss.o +net2kiss_LDADD = $(LDADD) +net2kiss_DEPENDENCIES = +net2kiss_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 +SOURCES = kissattach.c kissnetd.c kissparms.c mkiss.c net2kiss.c +OBJECTS = kissattach.o kissnetd.o kissparms.o mkiss.o net2kiss.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 kiss/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: + +kissattach: $(kissattach_OBJECTS) $(kissattach_DEPENDENCIES) + @rm -f kissattach + $(LINK) $(kissattach_LDFLAGS) $(kissattach_OBJECTS) $(kissattach_LDADD) $(LIBS) + +kissnetd: $(kissnetd_OBJECTS) $(kissnetd_DEPENDENCIES) + @rm -f kissnetd + $(LINK) $(kissnetd_LDFLAGS) $(kissnetd_OBJECTS) $(kissnetd_LDADD) $(LIBS) + +kissparms: $(kissparms_OBJECTS) $(kissparms_DEPENDENCIES) + @rm -f kissparms + $(LINK) $(kissparms_LDFLAGS) $(kissparms_OBJECTS) $(kissparms_LDADD) $(LIBS) + +mkiss: $(mkiss_OBJECTS) $(mkiss_DEPENDENCIES) + @rm -f mkiss + $(LINK) $(mkiss_LDFLAGS) $(mkiss_OBJECTS) $(mkiss_LDADD) $(LIBS) + +net2kiss: $(net2kiss_OBJECTS) $(net2kiss_DEPENDENCIES) + @rm -f net2kiss + $(LINK) $(net2kiss_LDFLAGS) $(net2kiss_OBJECTS) $(net2kiss_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 $(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 = kiss + +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 +kissattach.o: kissattach.c ../config.h ../pathnames.h +kissnetd.o: kissnetd.c +kissparms.o: kissparms.c ../config.h +mkiss.o: mkiss.c ../config.h +net2kiss.o: net2kiss.c + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-sbinPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ +clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile install-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: + +# 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/kiss/kissattach.c b/kiss/kissattach.c new file mode 100644 index 0000000..149c2bd --- /dev/null +++ b/kiss/kissattach.c @@ -0,0 +1,289 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "../pathnames.h" + +static char *callsign; +static int speed = 0; +static int mtu = 0; +static int logging = FALSE; + +static void terminate(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + exit(0); +} + +static int readconfig(char *port) +{ + FILE *fp; + char buffer[90], *s; + int n = 0; + + if ((fp = fopen(CONF_AXPORTS_FILE, "r")) == NULL) { + fprintf(stderr, "kissattach: cannot open axports 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, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + if (strcmp(s, port) != 0) + continue; + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + callsign = strdup(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + speed = atoi(s); + + if ((s = strtok(NULL, " \t\r\n")) == NULL) { + fprintf(stderr, "kissattach: unable to parse line %d of the axports file\n", n); + return FALSE; + } + + if (mtu == 0) { + if ((mtu = atoi(s)) <= 0) { + fprintf(stderr, "kissattach: invalid paclen setting\n"); + return FALSE; + } + } + + fclose(fp); + + return TRUE; + } + + fclose(fp); + + fprintf(stderr, "kissattach: cannot find port %s in axports\n", port); + + return FALSE; +} + + +static int setifcall(int fd, char *name) +{ + char call[7]; + + if (ax25_aton_entry(name, call) == -1) + return FALSE; + + if (ioctl(fd, SIOCSIFHWADDR, call) != 0) { + close(fd); + perror("kissattach: SIOCSIFHWADDR"); + return FALSE; + } + + return TRUE; +} + + +static int startiface(char *dev, struct hostent *hp) +{ + struct ifreq ifr; + int fd; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("kissattach: 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("kissattach: SIOCSIFADDR"); + return FALSE; + } + } + + ifr.ifr_mtu = mtu; + + if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) { + perror("kissattach: SIOCSIFMTU"); + return FALSE; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("kissattach: 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("kissattach: SIOCSIFFLAGS"); + return FALSE; + } + + close(fd); + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + int fd; + int disc = N_AX25; + char dev[64]; + int v = 4; + struct hostent *hp = NULL; + + while ((fd = getopt(argc, argv, "i:lm:v")) != -1) { + switch (fd) { + case 'i': + if ((hp = gethostbyname(optarg)) == NULL) { + fprintf(stderr, "kissattach: invalid internet name/address - %s\n", optarg); + return 1; + } + break; + case 'l': + logging = TRUE; + break; + case 'm': + if ((mtu = atoi(optarg)) <= 0) { + fprintf(stderr, "kissattach: invalid mtu size - %s\n", optarg); + return 1; + } + break; + case 'v': + printf("kissattach: %s\n", VERSION); + return 0; + case ':': + case '?': + fprintf(stderr, "usage: kissattach [-i inetaddr] [-l] [-m mtu] [-v] ttyinterface port\n"); + return 1; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "usage: kissattach [-i inetaddr] [-l] [-m mtu] [-v] ttyinterface port\n"); + return 1; + } + + if (tty_is_locked(argv[optind])) { + fprintf(stderr, "kissattach: device %s already in use\n", argv[optind]); + return 1; + } + + if (!readconfig(argv[optind + 1])) + return 1; + + if ((fd = open(argv[optind], O_RDONLY | O_NONBLOCK)) == -1) { + perror("kissattach: open"); + return 1; + } + + if (speed != 0 && !tty_speed(fd, speed)) + return 1; + + if (ioctl(fd, TIOCSETD, &disc) == -1) { + perror("kissattach: TIOCSETD"); + return 1; + } + + if (ioctl(fd, SIOCGIFNAME, dev) == -1) { + perror("kissattach: SIOCGIFNAME"); + return 1; + } + + if (!setifcall(fd, callsign)) + return 1; + + /* Now set the encapsulation */ + if (ioctl(fd, SIOCSIFENCAP, &v) == -1) { + perror("kissattach: SIOCSIFENCAP"); + return 1; + } + + if (!startiface(dev, hp)) + return 1; + + printf("AX.25 port %s bound to device %s\n", argv[optind + 1], dev); + + if (logging) { + openlog("kissattach", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "AX.25 port %s bound to device %s\n", argv[optind + 1], dev); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGTERM, terminate); + + /* + * Become a daemon if we can. + */ + if (!daemon_start(FALSE)) { + fprintf(stderr, "kissattach: cannot become a daemon\n"); + return 1; + } + + if (!tty_lock(argv[optind])) + return 1; + + while (1) + sleep(10000); + + /* NOT REACHED */ + return 0; +} diff --git a/kiss/kissnetd.c b/kiss/kissnetd.c new file mode 100644 index 0000000..ff38779 --- /dev/null +++ b/kiss/kissnetd.c @@ -0,0 +1,257 @@ +/* + * kissnetd.c : Simple kiss broadcast daemon between several + * pseudo-tty devices. + * Each kiss frame received on one pty is broadcasted + * to each other one. + * + * ATEPRA FPAC/Linux Project + * + * F1OAT 960804 - Frederic RIBLE + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *Version = "1.5"; +static int VerboseMode = 0; +static int MaxFrameSize = 512; + +#define REOPEN_TIMEOUT 30 /* try tio reopen every 10 s */ + +struct PortDescriptor { + char Name[80]; + int Fd; + unsigned char *FrameBuffer; + int BufferIndex; + time_t TimeLastOpen; +}; + +static struct PortDescriptor *PortList[FD_SETSIZE]; +static int NbPort = 0; + +static void Usage(void) +{ + fprintf(stderr, "\nUsage : kissnetd [-v] [-f size] /dev/pty?? [/dev/pty??]*\n"); + fprintf(stderr, " -v : Verbose mode, trace on stdout\n"); + fprintf(stderr, " -f size : Set max frame size to size bytes (default 512)\n"); + exit(1); +} + +static void Banner(int Small) +{ + if (Small) { + printf("kissnetd V %s by Frederic RIBLE F1OAT - ATEPRA FPAC/Linux Project\n", Version); + } + else { + printf("****************************************\n"); + printf("* Network broadcast between kiss ports *\n"); + printf("* ATEPRA FPAC/Linux Project *\n"); + printf("****************************************\n"); + printf("* kissnetd Version %-4s *\n", Version); + printf("* by Frederic RIBLE F1OAT *\n"); + printf("****************************************\n"); + } +} + +static void NewPort(char *Name) +{ + struct PortDescriptor *MyPort; + + if (VerboseMode) { + printf("Opening port %s\n", Name); + } + + if (NbPort == FD_SETSIZE) { + fprintf(stderr, "Cannot handle %s : too many ports\n", Name); + exit(1); + } + + MyPort = calloc(sizeof(struct PortDescriptor), 1); + if (MyPort) MyPort->FrameBuffer = calloc(sizeof (unsigned char), MaxFrameSize); + if (!MyPort || !MyPort->FrameBuffer) { + perror("cannot allocate port descriptor"); + exit(1); + } + + strncpy(MyPort->Name, Name, sizeof(MyPort->Name)); + MyPort->Fd = -1; + MyPort->FrameBuffer[0] = 0xC0; + MyPort->BufferIndex = 1; + PortList[NbPort++] = MyPort; +} + +static void ReopenPort(int PortNumber) +{ + char MyString[80]; + + PortList[PortNumber]->TimeLastOpen = time(NULL); + + if (VerboseMode) { + printf("Reopening port %d\n", PortNumber); + } + + syslog(LOG_WARNING, "kissnetd : Opening port %s\n", PortList[PortNumber]->Name); + + PortList[PortNumber]->Fd = open(PortList[PortNumber]->Name, O_RDWR | O_NONBLOCK); + if (PortList[PortNumber]->Fd < 0) { + syslog(LOG_WARNING, "kissnetd : Error opening port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) { + sprintf(MyString, "cannot reopen %s", PortList[PortNumber]->Name); + perror(MyString); + } + } +} + +static void TickReopen(void) +{ + int i; + time_t CurrentTime = time(NULL); + + for (i=0; iFd >= 0) continue; + if ( (CurrentTime - PortList[i]->TimeLastOpen) > REOPEN_TIMEOUT ) ReopenPort(i); + } +} + +static void Broadcast(int InputPort) +{ + int i; + int rc; + + /* Broadcast only info frames */ + + if (PortList[InputPort]->FrameBuffer[1] != 0x00) return; + + for (i=0; iFd < 0) continue; + rc = write(PortList[i]->Fd, + PortList[InputPort]->FrameBuffer, + PortList[InputPort]->BufferIndex); + if (VerboseMode) { + printf("Sending %d bytes on port %d : rc=%d\n", + PortList[InputPort]->BufferIndex, + i, rc); + } + } +} + +static void ProcessInput(int PortNumber) +{ + static unsigned char MyBuffer[2048]; + int Length; + int i; + struct PortDescriptor *MyPort = PortList[PortNumber]; + + Length = read(MyPort->Fd, MyBuffer, sizeof(MyBuffer)); + if (VerboseMode) { + printf("Read port %d : rc=%d\n", PortNumber, Length); + } + if (!Length) return; + if (Length < 0) { + syslog(LOG_WARNING, "kissnetd : Error reading port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) perror("read"); + close(MyPort->Fd); + MyPort->Fd = -1; + return; + } + for (i=0; iBufferIndex == MaxFrameSize) { + if (MyBuffer[i] == 0xC0) { + if (VerboseMode) printf("Drop frame too long\n"); + MyPort->BufferIndex = 1; + } + } + else { + MyPort->FrameBuffer[MyPort->BufferIndex++] = MyBuffer[i]; + if (MyBuffer[i] == 0xC0) { + Broadcast(PortNumber); + MyPort->BufferIndex = 1; + } + } + } +} + +static void ProcessPortList(void) +{ + static fd_set MyFdSet; + int i, rc; + struct timeval Timeout; + + Timeout.tv_sec = 1; + Timeout.tv_usec = 0; + + FD_ZERO(&MyFdSet); + for (i=0; iFd >= 0) FD_SET(PortList[i]->Fd, &MyFdSet); + } + rc = select(FD_SETSIZE, &MyFdSet, NULL, NULL, &Timeout); + + if (VerboseMode) printf("select : rc=%d\n", rc); + if (!rc ) TickReopen(); + + if (rc > 0) { + for (i=0; iFd < 0) continue; + if (FD_ISSET(PortList[i]->Fd, &MyFdSet)) { + ProcessInput(i); + rc--; + } + } + } +} + +static void ProcessArgv(char *argv[]) +{ + char *Opt; + int ArgvIndex = 0; + + while (argv[ArgvIndex]) { + if (argv[ArgvIndex][0] != '-') { + NewPort(argv[ArgvIndex++]); + continue; + } + for (Opt = &argv[ArgvIndex++][1]; *Opt; Opt++) { + switch (*Opt) { + case 'v': + VerboseMode = 1; + break; + case 'f': + MaxFrameSize = atoi(argv[ArgvIndex++]); + break; + default: + fprintf(stderr, "Invalid option %c\n", *Opt); + Usage(); + break; + } + } + + } +} + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + Banner(0); + Usage(); + } + else { + Banner(1); + } + + ProcessArgv(argv+1); + while (1) ProcessPortList(); + return 0; +} diff --git a/kiss/kissparms.c b/kiss/kissparms.c new file mode 100644 index 0000000..0a1a101 --- /dev/null +++ b/kiss/kissparms.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_FECLEVEL 8 +#define PARAM_RETURN 255 + +#define USAGE "usage: kissparms -p [-f y|n] [-h hw] [-l txtail] \ + [-r pers ] [-s slot] [-t txd] [-e feclevel] [-v] [-x]\n" + +int main(int argc, char *argv[]) +{ + unsigned char buffer[2]; + struct sockaddr sa; + int proto = ETH_P_AX25; + int txdelay = -1; + int txtail = -1; + int persist = -1; + int slottime = -1; + int fulldup = -1; + int hardware = -1; + int feclevel = -1; + int kissoff = 0; + int buflen, s; + char *port = NULL; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "kissparms: no AX.25 ports configured\n"); + return 1; + } + + while ((s = getopt(argc, argv, "e:f:h:l:p:r:s:t:vx")) != -1) { + switch (s) { + case 'e': + feclevel = atoi(optarg); + if (feclevel < 0 || feclevel > 3) { + fprintf(stderr, "kissparms: invalid FEC level value\n"); + return 1; + } + break; + + case 'f': + if (*optarg != 'y' && *optarg != 'n') { + fprintf(stderr, "kissparms: invalid full duplex setting\n"); + return 1; + } + fulldup = *optarg == 'y'; + break; + + case 'l': + txtail = atoi(optarg) / 10; + if (txtail < 0 || txtail > 255) { + fprintf(stderr, "kissparms: invalid txtail value\n"); + return 1; + } + break; + + + case 'h': + hardware = atoi(optarg); + if (hardware < 0 || hardware > 255) { + fprintf(stderr, "kissparms: invalid hardware value\n"); + return 1; + } + break; + + case 'p': + port = optarg; + if (ax25_config_get_addr(port) == NULL) { + fprintf(stderr, "kissparms: invalid port name - %s\n", port); + return 1; + } + break; + + case 'r': + persist = atoi(optarg); + if (persist < 0 || persist > 255) { + fprintf(stderr, "kissparms: invalid persist value\n"); + return 1; + } + break; + + case 's': + slottime = atoi(optarg) / 10; + if (slottime < 0 || slottime > 255) { + fprintf(stderr, "kissparms: invalid slottime value\n"); + return 1; + } + break; + + case 't': + txdelay = atoi(optarg) / 10; + if (txdelay < 0 || txdelay > 255) { + fprintf(stderr, "kissparms: invalid txdelay value\n"); + return 1; + } + break; + + case 'v': + printf("kissparms: %s\n", VERSION); + return 0; + + case 'x': + kissoff = 1; + break; + + case ':': + case '?': + fprintf(stderr, USAGE); + return 1; + } + } + + if (port == NULL) { + fprintf(stderr, USAGE); + return 1; + } + + if ((s = socket(AF_INET, SOCK_PACKET, htons(proto))) < 0) { + perror("kissparms: socket"); + return 1; + } + + strcpy(sa.sa_data, ax25_config_get_dev(port)); + + if (kissoff) { + buffer[0] = PARAM_RETURN; + buflen = 1; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } else { + if (txdelay != -1) { + buffer[0] = PARAM_TXDELAY; + buffer[1] = txdelay; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (txtail != -1) { + buffer[0] = PARAM_TXTAIL; + buffer[1] = txtail; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (persist != -1) { + buffer[0] = PARAM_PERSIST; + buffer[1] = persist; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (slottime != -1) { + buffer[0] = PARAM_SLOTTIME; + buffer[1] = slottime; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (fulldup != -1) { + buffer[0] = PARAM_FULLDUP; + buffer[1] = fulldup; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + if (hardware != -1) { + buffer[0] = PARAM_HARDWARE; + buffer[1] = hardware; + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + + if (feclevel != -1) { + buffer[0] = PARAM_FECLEVEL; + buffer[1] = feclevel; + + buflen = 2; + if (sendto(s, buffer, buflen, 0, &sa, sizeof(struct sockaddr)) == -1) { + perror("kissparms: sendto"); + return 1; + } + } + } + + close(s); + + return 0; +} diff --git a/kiss/mkiss.c b/kiss/mkiss.c new file mode 100644 index 0000000..8621ce4 --- /dev/null +++ b/kiss/mkiss.c @@ -0,0 +1,512 @@ +/* + * mkiss.c + * Fake out AX.25 code into supporting dual port TNCS by routing serial + * port data to/from two pseudo ttys. + * + * Version 1.03 + * + * N0BEL + * Kevin Uhlir + * kevinu@flochart.com + * + * 1.01 12/30/95 Ron Curry - Fixed FD_STATE bug where FD_STATE was being used for + * three state machines causing spurious writes to wrong TNC port. FD_STATE is + * now used for real serial port, FD0_STATE for first psuedo tty, and FD1_STATE + * for second psuedo tty. This was an easy fix but a MAJOR bug. + * + * 1.02 3/1/96 Jonathan Naylor - Make hardware handshaking default to off. + * Allowed for true multiplexing of the data from the two pseudo ttys. + * Numerous formatting changes. + * + * 1.03 4/20/96 Tomi Manninen - Rewrote KISS en/decapsulation (much of the + * code taken from linux/drivers/net/slip.c). Added support for all the 16 + * possible kiss ports and G8BPQ-style checksumming on ttyinterface. Now + * mkiss also sends a statistic report to stderr if a SIGUSR1 is sent to it. + * + * 1.04 25/5/96 Jonathan Naylor - Added check for UUCP style tty lock files. + * As they are now supported by kissattach as well. + * + * 1.05 20/8/96 Jonathan Naylor - Convert to becoming a daemon and added + * system logging. + * + * 1.06 23/11/96 Tomi Manninen - Added simple support for polled kiss. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define SIZE 4096 + +#define FEND 0300 /* Frame End (0xC0) */ +#define FESC 0333 /* Frame Escape (0xDB) */ +#define TFEND 0334 /* Transposed Frame End (0xDC) */ +#define TFESC 0335 /* Transposed Frame Escape (0xDD) */ + +#define POLL 0x0E + +/* + * Keep these off the stack. + */ +static unsigned char ibuf[SIZE]; /* buffer for input operations */ +static unsigned char obuf[SIZE]; /* buffer for kiss_tx() */ + +static int crc_errors = 0; +static int invalid_ports = 0; +static int return_polls = 0; + +static char *usage_string = "usage: mkiss [-p] [-c] [-h] [-l] [-s speed] [-v] ttyinterface pty ...\n"; + +static int dump_report = FALSE; + +static int logging = FALSE; +static int crcflag = FALSE; +static int hwflag = FALSE; +static int pollflag = FALSE; + +struct iface +{ + char *name; /* Interface name (/dev/???) */ + int fd; /* File descriptor */ + int escaped; /* FESC received? */ + unsigned char crc; /* Incoming frame crc */ + unsigned char obuf[SIZE]; /* TX buffer */ + unsigned char *optr; /* Next byte to transmit */ + unsigned int errors; /* KISS protocol error count */ + unsigned int nondata; /* Non-data frames rx 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 */ +}; + +static int poll(int fd, int ports) +{ + char buffer[3]; + static int port = 0; + + buffer[0] = FEND; + buffer[1] = POLL | (port << 4); + buffer[2] = FEND; + if (write(fd, buffer, 3) == -1) { + perror("mkiss: poll: write"); + return 1; + } + if (++port >= ports) + port = 0; + return 0; +} + +static int kiss_tx(int fd, int port, unsigned char *s, int len, int usecrc) +{ + unsigned char *ptr = obuf; + unsigned char c; + unsigned char crc = 0; + int first = TRUE; + + /* Non-data frames don't get a checksum byte */ + if ((s[0] & 0x0F) != 0) + usecrc = FALSE; + + /* Allow for checksum byte */ + if (usecrc) + len++; + + /* + * Send an initial FEND character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = FEND; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + c = *s++; + if (first) { /* Control byte */ + c = (c & 0x0F) | (port << 4); + first = FALSE; + } + if (usecrc) { + if (len == 0) /* Now past user data... */ + c = crc; /* ...time to encode cksum */ + else + crc ^= c; /* Adjust checksum */ + } + switch (c) { + case FEND: + *ptr++ = FESC; + *ptr++ = TFEND; + break; + case FESC: + *ptr++ = FESC; + *ptr++ = TFESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = FEND; + return write(fd, obuf, ptr - obuf); +} + +static int kiss_rx(struct iface *ifp, unsigned char c, int usecrc) +{ + int len; + + switch (c) { + case FEND: + len = ifp->optr - ifp->obuf; + if (len != 0 && ifp->escaped) { /* protocol error... */ + len = 0; /* ...drop frame */ + ifp->errors++; + } + if (len != 0 && (ifp->obuf[0] & 0x0F) != 0) { + /* + * Non-data frames don't have checksum. + */ + usecrc = 0; + if ((ifp->obuf[0] & 0x0F) == POLL) { + len = 0; /* drop returned polls */ + return_polls++; + } else + ifp->nondata++; + } + if (len != 0 && usecrc) { + if (ifp->crc != 0) { /* checksum failed... */ + len = 0; /* ...drop frame */ + crc_errors++; + } else + len--; /* delete checksum byte */ + } + if (len != 0) { + ifp->rxpackets++; + ifp->rxbytes += len; + } + /* + * Clean up. + */ + ifp->optr = ifp->obuf; + ifp->crc = 0; + ifp->escaped = FALSE; + return len; + case FESC: + ifp->escaped = TRUE; + return 0; + case TFESC: + if (ifp->escaped) { + ifp->escaped = FALSE; + c = FESC; + } + break; + case TFEND: + if (ifp->escaped) { + ifp->escaped = FALSE; + c = FEND; + } + break; + default: + if (ifp->escaped) { /* protocol error... */ + ifp->escaped = FALSE; + ifp->errors++; + } + break; + } + *ifp->optr++ = c; + if (usecrc) + ifp->crc ^= c; + return 0; +} + +static void sigterm_handler(int sig) +{ + if (logging) { + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); + } + + 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, "Hardware handshaking %sabled.", + hwflag ? "en" : "dis"); + syslog(LOG_INFO, "G8BPQ checksumming %sabled.", + crcflag ? "en" : "dis"); + syslog(LOG_INFO, "polling %sabled.", + pollflag ? "en" : "dis"); + 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, "Checksum errors: %d", crc_errors); + syslog(LOG_INFO, "Invalid ports: %d", invalid_ports); + syslog(LOG_INFO, "Returned polls: %d", return_polls); + 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[]) +{ + struct iface *pty[16]; + struct iface *tty; + unsigned char *icp; + int topfd; + fd_set readfd; + struct timeval timeout; + int retval, numptys, i, size, len; + int speed = -1; + + while ((size = getopt(argc, argv, "chlps:v")) != -1) { + switch (size) { + case 'c': + crcflag = TRUE; + break; + case 'h': + hwflag = TRUE; + break; + case 'l': + logging = TRUE; + break; + case 'p': + pollflag = TRUE; + break; + case 's': + speed = atoi(optarg); + break; + case 'v': + printf("mkiss: %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) > 16) { + fprintf(stderr, "mkiss: max 16 pty interfaces allowed.\n"); + return 1; + } + + /* + * Check for lock files before opening any TTYs + */ + if (tty_is_locked(argv[optind])) { + fprintf(stderr, "mkiss: 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, "mkiss: 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("mkiss: malloc"); + return 1; + } + + if ((tty->fd = open(argv[optind], O_RDWR | O_NDELAY)) == -1) { + perror("mkiss: open"); + return 1; + } + + tty->name = argv[optind]; + tty_raw(tty->fd, hwflag); + if (speed != -1) tty_speed(tty->fd, speed); + tty->optr = tty->obuf; + 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("mkiss: malloc"); + return 1; + } + if ((pty[i]->fd = open(argv[optind + i + 1], O_RDWR)) == -1) { + perror("mkiss: open"); + return 1; + } + pty[i]->name = argv[optind + i + 1]; + tty_raw(pty[i]->fd, FALSE); + pty[i]->optr = pty[i]->obuf; + 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, "mkiss: cannot become a daemon\n"); + return 1; + } + + if (logging) { + openlog("mkiss", 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); + + if (pollflag) { + timeout.tv_sec = 1; + timeout.tv_usec = 0; + } + + errno = 0; + retval = select(topfd + 1, &readfd, NULL, NULL, pollflag ? &timeout : NULL); + + if (retval == -1) { + if (dump_report) { + if (logging) + report(tty, pty, numptys); + dump_report = FALSE; + continue; + } else { + perror("mkiss: select"); + continue; + } + } + + /* + * Timer expired. + */ + if (retval == 0 && pollflag) { + poll(tty->fd, numptys); + 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 = kiss_rx(tty, *icp, crcflag)) != 0) { + if ((i = (*tty->obuf & 0xF0) >> 4) < numptys) { + kiss_tx(pty[i]->fd, 0, tty->obuf, len, FALSE); + pty[i]->txpackets++; + pty[i]->txbytes += len; + } else + invalid_ports++; + if (pollflag) + poll(tty->fd, numptys); + } + } + } + + 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 = kiss_rx(pty[i], *icp, FALSE)) != 0) { + kiss_tx(tty->fd, i, pty[i]->obuf, len, crcflag); + 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/kiss/net2kiss.c b/kiss/net2kiss.c new file mode 100644 index 0000000..19a7385 --- /dev/null +++ b/kiss/net2kiss.c @@ -0,0 +1,643 @@ +/*****************************************************************************/ + +/* + * net2kiss.c - convert a network interface to KISS data stream + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.1 18.09.96 Started + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* --------------------------------------------------------------------- */ + +static int fdif, fdpty; +static struct ifreq ifr; +static char *progname; +static int verbose = 0; + +/* --------------------------------------------------------------------- */ + +static void die(char *func) +{ + fprintf(stderr, "%s: %s (%i)%s%s\n", progname, strerror(errno), + errno, func ? " in " : "", func ? func : ""); + exit(-1); +} + +/* --------------------------------------------------------------------- */ + +static void display_packet(unsigned char *bp, unsigned int len) +{ + unsigned char v1=1,cmd=0; + unsigned char i,j; + + if (!bp || !len) + return; + if (len < 8) + return; + if (bp[1] & 1) { + /* + * FlexNet Header Compression + */ + v1 = 0; + cmd = (bp[1] & 2) != 0; + printf("fm ? to "); + i = (bp[2] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[2] << 4) | ((bp[3] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[3] << 2) | ((bp[4] >> 6) & 3)) & 0x3f; + if (i) + printf("%c",i+0x20); + i = bp[4] & 0x3f; + if (i) + printf("%c",i+0x20); + i = (bp[5] >> 2) & 0x3f; + if (i) + printf("%c",i+0x20); + i = ((bp[5] << 4) | ((bp[6] >> 4) & 0xf)) & 0x3f; + if (i) + printf("%c",i+0x20); + printf("-%u QSO Nr %u", bp[6] & 0xf, (bp[0] << 6) | + (bp[1] >> 2)); + bp += 7; + len -= 7; + } else { + /* + * normal header + */ + if (len < 15) + return; + if ((bp[6] & 0x80) != (bp[13] & 0x80)) { + v1 = 0; + cmd = (bp[6] & 0x80); + } + printf("fm "); + for(i = 7; i < 13; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u to ",(bp[13] >> 1) & 0xf); + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u",(bp[6] >> 1) & 0xf); + bp += 14; + len -= 14; + if ((!(bp[-1] & 1)) && (len >= 7)) printf(" via "); + while ((!(bp[-1] & 1)) && (len >= 7)) { + for(i = 0; i < 6; i++) + if ((bp[i] &0xfe) != 0x40) + printf("%c",bp[i] >> 1); + printf("-%u",(bp[6] >> 1) & 0xf); + bp += 7; + len -= 7; + if ((!(bp[-1] & 1)) && (len >= 7)) + printf(","); + } + } + if(!len) + return; + i = *bp++; + len--; + j = v1 ? ((i & 0x10) ? '!' : ' ') : + ((i & 0x10) ? (cmd ? '+' : '-') : (cmd ? '^' : 'v')); + if (!(i & 1)) { + /* + * Info frame + */ + printf(" I%u%u%c",(i >> 5) & 7,(i >> 1) & 7,j); + } else if (i & 2) { + /* + * U frame + */ + switch (i & (~0x10)) { + case 0x03: + printf(" UI%c",j); + break; + case 0x2f: + printf(" SABM%c",j); + break; + case 0x43: + printf(" DISC%c",j); + break; + case 0x0f: + printf(" DM%c",j); + break; + case 0x63: + printf(" UA%c",j); + break; + case 0x87: + printf(" FRMR%c",j); + break; + default: + printf(" unknown U (0x%x)%c",i & (~0x10),j); + break; + } + } else { + /* + * supervisory + */ + switch (i & 0xf) { + case 0x1: + printf(" RR%u%c",(i >> 5) & 7,j); + break; + case 0x5: + printf(" RNR%u%c",(i >> 5) & 7,j); + break; + case 0x9: + printf(" REJ%u%c",(i >> 5) & 7,j); + break; + default: + printf(" unknown S (0x%x)%u%c", i & 0xf, + (i >> 5) & 7, j); + break; + } + } + if (!len) { + printf("\n"); + return; + } + printf(" pid=%02X\n", *bp++); + len--; + j = 0; + while (len) { + i = *bp++; + if ((i >= 32) && (i < 128)) + printf("%c",i); + else if (i == 13) { + if (j) + printf("\n"); + j = 0; + } else + printf("."); + if (i >= 32) + j = 1; + len--; + } + if (j) + printf("\n"); +} + +/* ---------------------------------------------------------------------- */ + +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + char line[] = "/dev/ptyXX"; + const char *cp1, *cp2; + int master, slave; + struct group *gr = getgrnam("tty"); + + for (cp1 = "pqrstuvwxyzPQRST"; *cp1; cp1++) { + line[8] = *cp1; + for (cp2 = "0123456789abcdef"; *cp2; cp2++) { + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno == ENOENT) + return (-1); /* out of ptys */ + } else { + line[5] = 't'; + (void) chown(line, getuid(), + gr ? gr->gr_gid : -1); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +#if 0 + (void) revoke(line); +#endif + if ((slave = open(line, O_RDWR, 0)) != -1) { + *amaster = master; + *aslave = slave; + if (name) + strcpy(name, line); + if (termp) + (void) tcsetattr(slave, + TCSAFLUSH, + termp); + if (winp) + (void) ioctl(slave, + TIOCSWINSZ, + (char *)winp); + return 0; + } + (void) close(master); + line[5] = 'p'; + } + } + } + errno = ENOENT; /* out of ptys */ + return (-1); +} + +/* ---------------------------------------------------------------------- */ + +static void restore_ifflags(int signum) +{ + if (ioctl(fdif, SIOCSIFFLAGS, &ifr) < 0) + die("ioctl SIOCSIFFLAGS"); + close(fdif); + close(fdpty); + exit(0); +} + +/* --------------------------------------------------------------------- */ + +#define KISS_FEND ((unsigned char)0300) +#define KISS_FESC ((unsigned char)0333) +#define KISS_TFEND ((unsigned char)0334) +#define KISS_TFESC ((unsigned char)0335) + +#define KISS_CMD_DATA 0 +#define KISS_CMD_TXDELAY 1 +#define KISS_CMD_PPERSIST 2 +#define KISS_CMD_SLOTTIME 3 +#define KISS_CMD_TXTAIL 4 +#define KISS_CMD_FULLDUP 5 + +#define KISS_HUNT 0 +#define KISS_RX 1 +#define KISS_ESCAPED 2 + +/* --------------------------------------------------------------------- */ + +static void kiss_overflow(void) +{ + if (verbose) + printf("KISS: packet overflow\n"); +} + +static void kiss_bad_escape(void) +{ + if (verbose) + printf("KISS: bad escape sequence\n"); +} + +static void display_kiss_packet(char *pfx, unsigned char *pkt, + unsigned int pktlen) +{ + if (!verbose) + return; + switch (*pkt) { + case KISS_CMD_DATA: + printf("%s: ", pfx); + display_packet(pkt+1, pktlen-1); + break; + + case KISS_CMD_TXDELAY: + printf("%s: txdelay = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_PPERSIST: + printf("%s: p persistence = %d\n", pfx, pkt[1]); + break; + + case KISS_CMD_SLOTTIME: + printf("%s: slottime = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_TXTAIL: + printf("%s: txtail = %dms\n", pfx, (int)pkt[1] * 10); + break; + + case KISS_CMD_FULLDUP: + printf("%s: %sduplex\n", pfx, pkt[1] ? "full" : "half"); + break; + + default: + printf("%s: unknown frame type 0x%02x, length %d\n", pfx, + *pkt, pktlen); + } +} + +static void kiss_packet(int fdif, char *addr, + unsigned char *pkt, unsigned int pktlen) +{ + struct sockaddr to; + int i; + + if (pktlen < 2) + return; + display_kiss_packet("KISS", pkt, pktlen); + strncpy(to.sa_data, addr, sizeof(to.sa_data)); + i = sendto(fdif, pkt, pktlen, 0, &to, sizeof(to)); + if (i >= 0) + return; + if (errno == EMSGSIZE) { + if (verbose) + printf("sendto: %s: packet (size %d) too " + "long\n", addr, pktlen-1); + return; + } + if (errno == EWOULDBLOCK) { + if (verbose) + printf("sendto: %s: busy\n", addr); + return; + } + die("sendto"); + return; +} + +/* --------------------------------------------------------------------- */ + +static int doio(int fdif, int fdpty, char *ifaddr) +{ + unsigned char ibuf[2048]; + unsigned char *bp; + unsigned char pktbuf[2048]; + unsigned char *pktptr = pktbuf; + unsigned char pktstate = KISS_HUNT; + unsigned char obuf[16384]; + unsigned int ob_wp = 0, ob_rp = 0, ob_wpx; + int i; + fd_set rmask, wmask; + struct sockaddr from; + int from_len; + +#define ADD_CHAR(c) \ + obuf[ob_wpx] = c; \ + ob_wpx = (ob_wpx + 1) % sizeof(obuf); \ + if (ob_wpx == ob_rp) goto kissencerr; + +#define ADD_KISSCHAR(c) \ + if (((c) & 0xff) == KISS_FEND) \ + { ADD_CHAR(KISS_FESC); ADD_CHAR(KISS_TFEND); } \ + else if (((c) & 0xff) == KISS_FESC) \ + { ADD_CHAR(KISS_FESC); ADD_CHAR(KISS_TFESC); } \ + else { ADD_CHAR(c); } + + for (;;) { + FD_ZERO(&rmask); + FD_ZERO(&wmask); + FD_SET(fdif, &rmask); + FD_SET(fdpty, &rmask); + if (ob_rp != ob_wp) + FD_SET(fdpty, &wmask); + i = select((fdif > fdpty) ? fdif+1 : fdpty+1, &rmask, &wmask, + NULL, NULL); + if (i < 0) + die("select"); + if (FD_ISSET(fdpty, &wmask)) { + if (ob_rp > ob_wp) + i = write(fdpty, obuf+ob_rp, + sizeof(obuf)-ob_rp); + else + i = write(fdpty, obuf+ob_rp, ob_wp - ob_rp); + if (i < 0) + die("write"); + ob_rp = (ob_rp + i) % sizeof(obuf); + } + if (FD_ISSET(fdpty, &rmask)) { + i = read(fdpty, bp = ibuf, sizeof(ibuf)); + if (i < 0) { + if (errno != EIO) + die("read"); + return 0; + } + for (; i > 0; i--, bp++) { + switch (pktstate) { + default: + case KISS_HUNT: + if (*bp != KISS_FEND) + break; + pktptr = pktbuf; + pktstate = KISS_RX; + break; + + case KISS_RX: + if (*bp == KISS_FESC) { + pktstate = KISS_ESCAPED; + break; + } + if (*bp == KISS_FEND) { + kiss_packet(fdif, ifaddr, + pktbuf, + pktptr - pktbuf); + pktptr = pktbuf; + break; + } + if (pktptr >= pktbuf+sizeof(pktbuf)) { + kiss_overflow(); + pktstate = KISS_HUNT; + break; + } + *pktptr++ = *bp; + break; + + case KISS_ESCAPED: + if (pktptr >= pktbuf+sizeof(pktbuf)) { + kiss_overflow(); + pktstate = KISS_HUNT; + break; + } + if (*bp == KISS_TFESC) + *pktptr++ = KISS_FESC; + else if (*bp == KISS_TFEND) + *pktptr++ = KISS_FEND; + else { + kiss_bad_escape(); + pktstate = KISS_HUNT; + break; + } + pktstate = KISS_RX; + break; + } + } + } + if (FD_ISSET(fdif, &rmask)) { + from_len = sizeof(from); + i = recvfrom(fdif, bp = ibuf, sizeof(ibuf), 0, &from, + &from_len); + if (i < 0) { + if (errno == EWOULDBLOCK) + continue; + die("recvfrom"); + } + if (verbose) + display_kiss_packet(from.sa_data, ibuf, i); + ob_wpx = ob_wp; + ADD_CHAR(KISS_FEND); + for (; i > 0; i--, bp++) { + ADD_KISSCHAR(*bp); + } + ADD_CHAR(KISS_FEND); + ob_wp = ob_wpx; + } + continue; + kissencerr: + if (verbose) + printf("KISS: Encoder out of memory\n"); + } +#undef ADD_CHAR +#undef ADD_KISSCHAR +} + +/* --------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + struct ifreq ifr_new; + struct sockaddr sa; + char *name_iface = "bc0"; + char *name_pname = NULL; + char slavename[32]; + char *master_name; + struct termios termios; + int c; + int errflg = 0; + int symlnk = 0; + int symlnkforce = 0; + short if_newflags = 0; + int proto = htons(ETH_P_AX25); + + progname = argv[0]; + while ((c = getopt(argc, argv, "sfzvai:")) != EOF) { + switch (c) { + case 's': + symlnk = 1; + break; + case 'f': + symlnkforce = 1; + break; + case 'i': + name_iface = optarg; + break; + case 'z': + if_newflags |= IFF_PROMISC; + break; + case 'v': + verbose++; + break; + case 'a': + proto = htons(ETH_P_ALL); + break; + default: + errflg++; + break; + } + } + if (argc > optind) + name_pname = argv[optind]; + else + errflg++; + if (errflg) { + fprintf(stderr, "usage: %s [-s] [-f] [-i iface] " + "[-z] [-v] ptyname\n", progname); + exit(1); + } + if (symlnk) { + int fdtty; + + if (openpty(&fdpty, &fdtty, slavename, NULL, NULL)) { + fprintf(stderr, "%s: out of pseudoterminals\n", + progname); + exit(1); + } + close(fdtty); + fcntl(fdpty, F_SETFL, fcntl(fdpty, F_GETFL, 0) | O_NONBLOCK); + if (symlnkforce) + unlink(name_pname); + if (symlink(slavename, name_pname)) + perror("symlink"); + slavename[5] = 'p'; + master_name = slavename; + } else { + if ((fdpty = open(name_pname, + O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { + fprintf(stderr, "%s: cannot open \"%s\"\n", progname, + name_pname); + exit(1); + } + master_name = name_pname; + } + if ((fdif = socket(PF_INET, SOCK_PACKET, proto)) < 0) + die("socket"); + strcpy(sa.sa_data, name_iface); + sa.sa_family = AF_INET; + if (bind(fdif, &sa, sizeof(struct sockaddr)) < 0) + die("bind"); + strcpy(ifr.ifr_name, name_iface); + if (ioctl(fdif, SIOCGIFFLAGS, &ifr) < 0) + die("ioctl SIOCGIFFLAGS"); + ifr_new = ifr; + ifr_new.ifr_flags |= if_newflags; + if (ioctl(fdif, SIOCSIFFLAGS, &ifr_new) < 0) + die("ioctl SIOCSIFFLAGS"); + signal(SIGHUP, restore_ifflags); + signal(SIGINT, restore_ifflags); + signal(SIGTERM, restore_ifflags); + signal(SIGQUIT, restore_ifflags); + signal(SIGUSR1, restore_ifflags); + signal(SIGUSR2, restore_ifflags); + + for (;;) { + if (tcgetattr(fdpty, &termios)) + die("tcgetattr"); + termios.c_iflag = IGNBRK; + termios.c_oflag = 0; + termios.c_lflag = 0; + termios.c_cflag &= ~(CSIZE|CSTOPB|PARENB|HUPCL|CRTSCTS); + termios.c_cflag |= CS8|CREAD|CLOCAL; + if (tcsetattr(fdpty, TCSANOW, &termios)) + die("tsgetattr"); + if (doio(fdif, fdpty, name_iface)) + break; + /* + * try to reopen master + */ + if (verbose) + printf("reopening master tty: %s\n", master_name); + close(fdpty); + if ((fdpty = open(master_name, + O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { + fprintf(stderr, "%s: cannot reopen \"%s\"\n", progname, + master_name); + exit(1); + } + } + + restore_ifflags(0); + exit(0); +} + +/* --------------------------------------------------------------------- */ -- cgit v1.2.3