summaryrefslogtreecommitdiffstats
path: root/kiss
diff options
context:
space:
mode:
Diffstat (limited to 'kiss')
-rw-r--r--kiss/Makefile.am8
-rw-r--r--kiss/Makefile.in367
-rw-r--r--kiss/kissattach.c289
-rw-r--r--kiss/kissnetd.c257
-rw-r--r--kiss/kissparms.c221
-rw-r--r--kiss/mkiss.c512
-rw-r--r--kiss/net2kiss.c643
7 files changed, 2297 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/daemon.h>
+#include <netax25/axlib.h>
+#include <netax25/ttyutils.h>
+
+#include <config.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <errno.h>
+#include <syslog.h>
+#include <time.h>
+
+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; i<NbPort; i++) {
+ if (PortList[i]->Fd >= 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; i<NbPort; i++) {
+ if (i == InputPort) continue;
+ if (PortList[i]->Fd < 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; i<Length; i++) {
+ if (MyPort->BufferIndex == 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; i<NbPort; i++) {
+ if (PortList[i]->Fd >= 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; i<NbPort && rc; i++) {
+ if (PortList[i]->Fd < 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+
+#include <netax25/ax25.h>
+#include <netax25/axconfig.h>
+
+#include <config.h>
+
+#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 <port> [-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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/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>
+
+#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 <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <asm/byteorder.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <grp.h>
+#include <string.h>
+#include <termios.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+
+/* --------------------------------------------------------------------- */
+
+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);
+}
+
+/* --------------------------------------------------------------------- */