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/net2kiss.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 643 insertions(+) create mode 100644 kiss/net2kiss.c (limited to 'kiss/net2kiss.c') 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