summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Osterried <thomas@osterried.de>2005-10-30 10:31:40 +0000
committerThomas Osterried <thomas@osterried.de>2005-10-30 10:31:40 +0000
commitf3a4c67e9091c98596c19784040b88ad446a87cf (patch)
treed200e4c73346a29e72452a2a62e7263b8cdecbeb
parent20a2c84a1c4488ae730bcb8c0ae52a12624c1848 (diff)
- tun/tap support for ax25ipd
- fclose() fix in config.c description of tun/tap: added a new fast and efficient link to the linux kernel ax25 stack, via the ethertap interface. ax25 goes directly to the bpqether interface in the kernel via ethertap/tuntap interfaces, which is a much better way than traditional kissattach to a ttyp/ptyp pair.
-rw-r--r--ax25ipd/HISTORY.ax25ipd7
-rw-r--r--ax25ipd/Makefile.am3
-rw-r--r--ax25ipd/Makefile.in5
-rw-r--r--ax25ipd/ax25ipd.conf22
-rw-r--r--ax25ipd/ax25ipd.conf.52
-rw-r--r--ax25ipd/ax25ipd.h9
-rw-r--r--ax25ipd/bpqether.c342
-rw-r--r--ax25ipd/config.c1
-rw-r--r--ax25ipd/io.c24
-rw-r--r--ax25ipd/process.c12
10 files changed, 417 insertions, 10 deletions
diff --git a/ax25ipd/HISTORY.ax25ipd b/ax25ipd/HISTORY.ax25ipd
index f4a28cd..20a6339 100644
--- a/ax25ipd/HISTORY.ax25ipd
+++ b/ax25ipd/HISTORY.ax25ipd
@@ -46,4 +46,11 @@
* July97 Added support for broadcast addresses and routes.
* Converted route array to a linked list and removed the
* maximum route limitations. (vk2ktj)
+ *
+ * 2005-10-26 - dl9sau:
+ * added a new fast and efficient link to the linux kernel ax25
+ * stack, via the ethertap interface.
+ * ax25 goes directly to the bpqether interface in the kernel via
+ * ethertap/tuntap interfaces, which is a much better way than
+ * traditional kissattach to a ttyp/ptyp pair.
*/
diff --git a/ax25ipd/Makefile.am b/ax25ipd/Makefile.am
index 66b23dd..39ef22f 100644
--- a/ax25ipd/Makefile.am
+++ b/ax25ipd/Makefile.am
@@ -19,7 +19,8 @@ ax25ipd_SOURCES = \
ax25ipd.c \
ax25ipd.h \
process.c \
- routing.c
+ routing.c \
+ bpqether.c
# Needed so that install is optional
etcfiles = ax25ipd.conf
diff --git a/ax25ipd/Makefile.in b/ax25ipd/Makefile.in
index 3d1fd23..8f67132 100644
--- a/ax25ipd/Makefile.in
+++ b/ax25ipd/Makefile.in
@@ -108,7 +108,8 @@ ax25ipd_SOURCES = \
ax25ipd.c \
ax25ipd.h \
process.c \
- routing.c
+ routing.c \
+ bpqether.c
# Needed so that install is optional
@@ -129,7 +130,7 @@ PROGRAMS = $(sbin_PROGRAMS)
am_ax25ipd_OBJECTS = config.$(OBJEXT) crc.$(OBJEXT) io.$(OBJEXT) \
kiss.$(OBJEXT) ax25ipd.$(OBJEXT) process.$(OBJEXT) \
- routing.$(OBJEXT)
+ routing.$(OBJEXT) bpqether.$(OBJEXT)
ax25ipd_OBJECTS = $(am_ax25ipd_OBJECTS)
ax25ipd_DEPENDENCIES =
ax25ipd_LDFLAGS =
diff --git a/ax25ipd/ax25ipd.conf b/ax25ipd/ax25ipd.conf
index 391494f..af28d32 100644
--- a/ax25ipd/ax25ipd.conf
+++ b/ax25ipd/ax25ipd.conf
@@ -27,10 +27,30 @@ mode tnc
#beacon after 540
#btext ax25ip -- tncmode rob/vk5xxx -- Experimental AXIP gateway
#
-# Serial port, or pipe connected to a kissattach in my case
#
+# Serial port, ethertap interface, or pipe connected to a kissattach in my case
+#
+# alternatively, if you have the kernel module bpqether:
+# if you use tun/tap or ethertap instead of kissattach you may say, without
+# leading slashes (!! - that's how ax25ipd consideres using the tty kiss
+# driver or tun/tap or ethertap):
+# with tun/tap:
+# device foobar
+# with ethertap (obsolete):
+# device tap0
+# make sure you set a mycall above, or say axparms foobar -setcall te1st
+# note: the device will be up when you assign an ip address
+# _after_ starting ax25rtd (which initializes the device), start ax25d
+# with bpqether or pty, you do not need to care abt the speed
+# tun/tap: as descriped in /usr/src/linux/Documentatioa/networking/tuntap.txt,
+# make a device # like this:
+# crw-r--r-- 1 root root 10, 200 Nov 26 13:32 tun
+# with the command mknod /dev/net/tun c 10 200
+#
+#device ampr
device /dev/ttyp0
#
+#
# Set the device speed
#
speed 9600
diff --git a/ax25ipd/ax25ipd.conf.5 b/ax25ipd/ax25ipd.conf.5
index 73ea569..d2f1561 100644
--- a/ax25ipd/ax25ipd.conf.5
+++ b/ax25ipd/ax25ipd.conf.5
@@ -66,7 +66,7 @@ mode tnc
.br
#
.br
-# Serial port, or pipe connected to a kissattach in my case
+# Serial port, ethertap interface, or pipe connected to a kissattach in my case
.br
#
.br
diff --git a/ax25ipd/ax25ipd.h b/ax25ipd/ax25ipd.h
index de845b8..818cd50 100644
--- a/ax25ipd/ax25ipd.h
+++ b/ax25ipd/ax25ipd.h
@@ -180,6 +180,15 @@ void usr1_handler(int);
void int_handler(int);
void term_handler(int);
+/* io.c */
+extern int ttyfd_bpq;
+
+/* bpqether.c */
+int send_bpq(unsigned char *buf, int len);
+int receive_bpq(unsigned char *buf, int l);
+int open_ethertap(char *ifname);
+int set_bpq_dev_call_and_up(char *ethertap_name);
+
/*
* end
*/
diff --git a/ax25ipd/bpqether.c b/ax25ipd/bpqether.c
new file mode 100644
index 0000000..58333f1
--- /dev/null
+++ b/ax25ipd/bpqether.c
@@ -0,0 +1,342 @@
+/* @(#) $Id: bpqether.c,v 1.1 2005/10/30 10:31:40 dl9sau Exp $ */
+
+extern int ttyfd;
+/*
+ * this is a port of wampes ethertap whith my extension for bpqether
+ *
+ * (c) 20020630 Thomas Osterried dl9sau
+ * License: GPL
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#ifdef linux
+
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+#ifndef LINUX_VERSION_CODE
+#define LINUX_VERSION_CODE KERNEL_VERSION(2,4,0)-1
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define TRY_TUNTAP 1
+#include <net/if.h>
+#include <linux/if_tun.h>
+#else
+#include <linux/if.h>
+#endif
+
+#endif /* linux */
+
+#include "ax25ipd.h"
+
+#define ETAP_MTU_MIN 256
+#define ETAP_MTU 1024
+#define ETAP_MTU_MAX 1500
+#ifndef MAX_FRAME
+#define MAX_FRAME 2048
+#endif
+
+#define ETHERTAP_HEADER_LEN_TUN 18
+#define ETHERTAP_HEADER_LEN_ETHERTAP 16
+#define ETHERTAP_HEADER_LEN_MAX ETHERTAP_HEADER_LEN_TUN
+
+struct ethertap_packet {
+ char ethernet_header[18];
+ char data[MAX_FRAME];
+};
+
+unsigned char hwaddr_remote[6];
+
+static int ethertap_header_len;
+
+/*---------------------------------------------------------------------------*/
+
+int send_bpq(unsigned char *buf, int l)
+{
+ struct ethertap_packet ethertap_packet;
+ void *addr = &ethertap_packet;
+ int offset = ETHERTAP_HEADER_LEN_MAX - ethertap_header_len;
+
+ static const unsigned char ethernet_header[18] = {
+ 0x00, 0x00, 0x00, 0x02, /* ??? ??? ETH_P_AX25 (16bit) */
+ 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, /* Destination address (kernel et
+hertap module) */
+ 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, /* Source address (WAMPES etherta
+p module) */
+ 0x08, 0xff /* Protocol (bpqether) */
+ };
+
+ if (l <= 0)
+ return -1;
+
+ if (l > (sizeof(ethertap_packet.data) - 2))
+ l = sizeof(ethertap_packet.data);
+ memcpy(ethertap_packet.data + 2, buf, l);
+ memcpy(ethertap_packet.ethernet_header, (const char *) ethernet_header, sizeof(ethernet_header));
+ memcpy(ethertap_packet.ethernet_header + 4, hwaddr_remote, 6);
+ memcpy(ethertap_packet.ethernet_header + 4 + 6 + 2, hwaddr_remote +2, 6 -2);
+ ethertap_packet.data[0] = (l + 5) % 256;
+ ethertap_packet.data[1] = (l + 5) / 256;
+ l += 2;
+
+ //send_tty(addr + offset, l + sizeof(ethertap_packet.ethernet_header) - offset);
+ write(ttyfd, addr + offset, l + sizeof(ethertap_packet.ethernet_header) - offset);
+ return l;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int receive_bpq(unsigned char *buf, int l)
+{
+ if ((l -= ethertap_header_len) <= 0 ||
+ buf[ethertap_header_len-2] & 0xff != 0x08 ||
+ buf[ethertap_header_len-1] & 0xff != 0xff) {
+ // not a bpqether packet.
+ // drop silently - ethernet.ax25 is not the only protocol spokenon ethernet ;)
+ return -1;
+ }
+ l -= 2;
+ if (l <= 0 && buf[ethertap_header_len] + buf[ethertap_header_len] * 256 - 5 != l) {
+ // length error in bpqether packet
+ return 0;
+ }
+
+ from_kiss(buf + ethertap_header_len + 2, l);
+ return l;
+}
+
+/*---------------------------------------------------------------------------*/
+/* TUN/TAP support for linux. ethertap is obsolete */
+
+#ifdef TRY_TUNTAP
+static int tun_alloc(char *dev)
+{
+ struct ifreq ifr;
+ int fd, err;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Flags: IFF_TUN - TUN device (no Ethernet headers)
+ * IFF_TAP - TAP device
+ *
+ * IFF_NO_PI - Do not provide packet information
+ */
+ ifr.ifr_flags = IFF_TAP;
+ if (*dev) {
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ }
+
+ if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
+ close(fd);
+ return err;
+ }
+ strcpy(dev, ifr.ifr_name);
+
+ /* persist mode */
+ //if (ioctl(fd, TUNSETPERSIST, 1) < 0)
+ //perror("TUNSETPERSIST");
+
+ /* don't checksum */
+ //if (ioctl(fd, TUNSETNOCSUM, 1) < 0)
+ //perror("TUNSETNOCSUM");
+
+ return fd;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+int open_ethertap(char *ifname)
+{
+
+ int fd;
+ char devname[PATH_MAX];
+ struct ifreq ifr;
+ struct stat statbuf;
+ int tuntap = 0;
+ int mtu = 0;
+ int skfd;
+
+ strcpy(devname, "/dev/");
+ strncpy(devname + 5, ifname, sizeof(devname) - 5 -1);
+ devname[sizeof(devname) -1] = 0;
+
+ // tuntap == 0: original ethertap. works on a real character device
+ if (!stat(devname, &statbuf)) {
+ fd = open(devname, O_RDWR);
+ if (fd < 0) {
+ LOGL2("%s: %s\n", devname, strerror(errno));
+ return -1;
+ }
+#ifdef TRY_TUNTAP
+ } else {
+ strcpy(devname, ifname);
+ if ((fd = tun_alloc(devname)) < 0) {
+ LOGL2("%s: %s\n", devname, strerror(errno));
+ return -1;
+ }
+ ifname = devname;
+ tuntap = 1;
+#endif
+ }
+ ethertap_header_len = (tuntap ? ETHERTAP_HEADER_LEN_TUN : ETHERTAP_HEADER_LEN_ETHERTAP);
+
+ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket()");
+ close(fd);
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+ perror("SIOCGIFFLAGS");
+
+ ifr.ifr_flags |= (IFF_UP | IFF_NOARP);
+ if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0)
+ perror("SIOCSIFFLAGS");
+
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) {
+ perror("SIOCGIFHWADDR");
+ hwaddr_remote[0] = 0xfe;
+ hwaddr_remote[1] = 0xfd;
+ hwaddr_remote[2] = 0x0;
+ hwaddr_remote[3] = 0x0;
+ hwaddr_remote[4] = 0x0;
+ hwaddr_remote[5] = 0x0;
+ } else
+ memcpy(hwaddr_remote, ifr.ifr_hwaddr.sa_data, 6);
+
+ if (ttyspeed > ETAP_MTU_MIN && ttyspeed != 9600) {
+ mtu = ttyspeed;
+ } else {
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
+ perror("SIOCGIFMTU");
+ else
+ mtu = ifr.ifr_mtu;
+ }
+ if (mtu < ETAP_MTU_MIN || mtu > ETAP_MTU_MAX)
+ mtu = ETAP_MTU;
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ ifr.ifr_mtu = mtu;
+ if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0)
+ perror("SIOSGIFMTU");
+
+ close(skfd);
+
+ return fd;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int set_bpq_dev_call_and_up(char *ifname)
+{
+ FILE * fp;
+ char buf[1024];
+ char bpq_name[IFNAMSIZ];
+ char dev_name[IFNAMSIZ];
+ struct ifreq ifr;
+ struct sockaddr *sa;
+ int drop;
+ int skfd;
+ int len;
+ int err = -1;
+
+ // 1. find correspondent bpqether device in /proc (i.e. bpq0 for tap0)
+ // 2. set the ax25 call of bpq0 (in this example)
+ // 3. ifup bpq0
+
+ if (!(fp = fopen("/proc/net/bpqether", "r"))) {
+ perror("/proc/net/bpqether");
+ return -1;
+ }
+
+ // look up bpqether devce in /proc:
+ // dev ether destination accept from
+ // bpq0 tap0 FF:FF:FF:FF:FF:FF *
+
+ drop = 1;
+ *bpq_name = *dev_name = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (drop) {
+ // header line
+ drop = 0;
+ continue;
+ }
+ sscanf(buf, "%s %s ", bpq_name, dev_name);
+ if (!strcmp(dev_name, ifname))
+ break;
+ *bpq_name = *dev_name = 0;
+ }
+ fclose(fp);
+ if (!*bpq_name) {
+ LOGL2("Did not found bpqether device for %s in /proc/net/bpqether: %s", ifr.ifr_name, strerror(errno));
+ return -1;
+ }
+
+ LOGL1("found bpq device %s for %s\n", bpq_name, dev_name);
+
+ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket()");
+ return -1;
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ memcpy(ifr.ifr_name, bpq_name, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+ ifr.ifr_hwaddr.sa_family = PF_AX25;
+ memcpy(ifr.ifr_hwaddr.sa_data, mycallsign, 7);
+
+ if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
+ perror("SIOCSIFHWADDR");
+ close(skfd);
+ return -1;
+ }
+ strncpy(ifr.ifr_name, bpq_name, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ ifr.ifr_mtu = 256;
+ if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0)
+ perror("SIOSGIFMTU");
+
+ strncpy(ifr.ifr_name, bpq_name, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
+ perror("SIOCGIFFLAGS");
+ ifr.ifr_flags = 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP);
+ if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ err = -1;
+ }
+
+ close(skfd);
+
+ return err;
+}
diff --git a/ax25ipd/config.c b/ax25ipd/config.c
index d78a333..e67ffcf 100644
--- a/ax25ipd/config.c
+++ b/ax25ipd/config.c
@@ -148,6 +148,7 @@ char *f;
exit(1);
}
}
+ fclose(cf);
}
/* Process each line from the config file. The return value is encoded. */
diff --git a/ax25ipd/io.c b/ax25ipd/io.c
index 9c59ac1..914255a 100644
--- a/ax25ipd/io.c
+++ b/ax25ipd/io.c
@@ -69,6 +69,8 @@ int fromlen;
time_t last_bc_time;
+int ttyfd_bpq = 0;
+
/*
* I/O modes for the io_error routine
*/
@@ -187,7 +189,7 @@ void io_open()
}
}
- ttyfd = open(ttydevice, O_RDWR, 0);
+ ttyfd = ((ttyfd_bpq = (strchr(ttydevice, '/') ? 0 : 1)) ? open_ethertap(ttydevice) : open(ttydevice, O_RDWR, 0));
if (ttyfd < 0) {
perror("opening tty device");
exit(1);
@@ -196,6 +198,10 @@ void io_open()
perror("setting non-blocking I/O on tty device");
exit(1);
}
+ if (ttyfd_bpq) {
+ set_bpq_dev_call_and_up(ttydevice);
+ goto behind_normal_tty;
+ }
#ifdef USE_TERMIOS
if (ioctl(ttyfd, TCGETS, &nterm) < 0) {
#endif
@@ -287,6 +293,8 @@ void io_open()
if (digi)
send_params();
+behind_normal_tty:
+
last_bc_time = 0; /* force immediate id */
}
@@ -354,14 +362,24 @@ void io_start() {
}
while (io_error(n, buf, n, READ_MSG, TTY_MODE));
LOGL4("ttydata l=%d\n", n);
- if (n > 0)
- assemble_kiss(buf, n);
+ if (n > 0) {
+ if (!ttyfd_bpq) {
+ assemble_kiss(buf, n);
+ } else {
+ // no crc on bpqether. but a MAC header
+ if (receive_bpq(buf, n) < 0) {
+ goto out_ttyfd;
+ }
+ }
+ }
+
/*
* If we are in "beacon after" mode, reset the "last_bc_time" each time
* we hear something on the channel.
*/
if (!bc_every)
last_bc_time = time(NULL);
+out_ttyfd:
}
if (udp_mode) {
diff --git a/ax25ipd/process.c b/ax25ipd/process.c
index 0b1308c..34c0fc7 100644
--- a/ax25ipd/process.c
+++ b/ax25ipd/process.c
@@ -198,7 +198,11 @@ int l;
}
#endif
} /* end of tnc mode */
- send_kiss(port, buf, l);
+ if (!ttyfd_bpq)
+ send_kiss(port, buf, l);
+ else {
+ send_bpq(buf, l);
+ }
}
/*
@@ -240,7 +244,11 @@ void do_beacon()
if (loglevel > 2)
dump_ax25frame("do_beacon: ", bcbuf, bclen);
stats.kiss_beacon_outs++;
- send_kiss(0, bcbuf, bclen);
+ if (!ttyfd_bpq)
+ send_kiss(0, bcbuf, bclen);
+ else {
+ send_bpq(bcbuf, bclen);
+ }
}
/*