aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2018-09-29 12:00:43 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2018-09-29 12:00:43 +0200
commit7db7b9fa379f88cd4d562dabf88102e070c8e2be (patch)
tree1f451cfe26971752871d9e351f5184b03563326f /src
downloadfldigi-kissattach-7db7b9fa379f88cd4d562dabf88102e070c8e2be.tar.gz
fldigi-kissattach-7db7b9fa379f88cd4d562dabf88102e070c8e2be.tar.bz2
fldigi-kissattach-7db7b9fa379f88cd4d562dabf88102e070c8e2be.zip
Commit initial version
Diffstat (limited to 'src')
-rw-r--r--src/kissattach.c234
-rw-r--r--src/main.rs136
2 files changed, 370 insertions, 0 deletions
diff --git a/src/kissattach.c b/src/kissattach.c
new file mode 100644
index 0000000..c39923d
--- /dev/null
+++ b/src/kissattach.c
@@ -0,0 +1,234 @@
+// Taken from ax25-tools 0.0.10-rc4 kissattach.c
+// SPDX-License-Identifier: GPL-2.0-only
+#include <stdio.h>
+#define __USE_XOPEN
+#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 <errno.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>
+
+#define FALSE 0
+#define TRUE 1
+
+static struct speed_struct {
+ int user_speed;
+ speed_t termios_speed;
+} speed_table[] = {
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+#ifdef B57600
+ {57600, B57600},
+#endif
+#ifdef B115200
+ {115200, B115200},
+#endif
+#ifdef B230400
+ {230400, B230400},
+#endif
+#ifdef B460800
+ {460800, B460800},
+#endif
+ {-1, B0}
+};
+
+static int tty_speed(int fd, int speed)
+{
+ struct termios term;
+ struct speed_struct *s;
+
+ for (s = speed_table; s->user_speed != -1; s++)
+ if (s->user_speed == speed)
+ break;
+
+ if (s->user_speed == -1) {
+ fprintf(stderr, "tty_speed: invalid speed %d\n", speed);
+ return FALSE;
+ }
+
+ if (tcgetattr(fd, &term) == -1) {
+ perror("tty_speed: tcgetattr");
+ return FALSE;
+ }
+
+ cfsetispeed(&term, s->termios_speed);
+ cfsetospeed(&term, s->termios_speed);
+
+ if (tcsetattr(fd, TCSANOW, &term) == -1) {
+ perror("tty_speed: tcsetattr");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int ax25_aton_entry(const char *name, char *buf)
+{
+ int ct = 0;
+ int ssid = 0;
+ const char *p = name;
+ char c;
+
+ while (ct < 6) {
+ c = toupper(*p);
+
+ if (c == '-' || c == '\0')
+ break;
+
+ if (!isalnum(c)) {
+ printf("axutils: invalid symbol in callsign '%s'\n", name);
+ return -1;
+ }
+
+ buf[ct] = c << 1;
+
+ p++;
+ ct++;
+ }
+
+ while (ct < 6) {
+ buf[ct] = ' ' << 1;
+ ct++;
+ }
+
+ if (*p != '\0') {
+ p++;
+
+ if (sscanf(p, "%d", &ssid) != 1 || ssid < 0 || ssid > 15) {
+ printf("axutils: SSID must follow '-' and be numeric in the range 0-15 - '%s'\n", name);
+ return -1;
+ }
+ }
+
+ buf[6] = ((ssid + '0') << 1) & 0x1E;
+
+ return 0;
+}
+
+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("SIOCSIFHWADDR");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static int startiface(char *dev, int mtu, int allow_broadcast)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return FALSE;
+ }
+
+ strcpy(ifr.ifr_name, dev);
+
+ ifr.ifr_mtu = mtu;
+
+ if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
+ perror("SIOCSIFMTU");
+ return FALSE;
+ }
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ perror("SIOCGIFFLAGS");
+ return FALSE;
+ }
+
+ ifr.ifr_flags &= IFF_NOARP;
+ ifr.ifr_flags |= IFF_UP;
+ ifr.ifr_flags |= IFF_RUNNING;
+ if (allow_broadcast)
+ ifr.ifr_flags |= IFF_BROADCAST; /* samba broadcasts are a pain.. */
+ else
+ ifr.ifr_flags &= ~(IFF_BROADCAST); /* samba broadcasts are a pain.. */
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return FALSE;
+ }
+
+ close(fd);
+
+ return TRUE;
+}
+
+int32_t kissattach(
+ char *callsign,
+ int32_t speed,
+ int32_t mtu,
+ char *kttyname,
+ int32_t allow_broadcast)
+{
+ int fd;
+ int disc = N_AX25;
+ char dev[64];
+
+ if ((fd = open(kttyname, O_RDONLY | O_NONBLOCK)) == -1) {
+ perror("open");
+ return 0;
+ }
+
+ if (speed != 0 && !tty_speed(fd, speed))
+ return 0;
+
+ if (ioctl(fd, TIOCSETD, &disc) == -1) {
+ //Error setting line discipline
+ perror("TIOCSETD");
+ fprintf(stderr, "Are you sure you have enabled %s support in the kernel\n",
+ disc == N_AX25 ? "MKISS" : "6PACK");
+ fprintf(stderr, "or, if you made it a module, that the module is loaded?\n");
+ return 0;
+ }
+
+ if (ioctl(fd, SIOCGIFNAME, dev) == -1) {
+ perror("SIOCGIFNAME");
+ return 0;
+ }
+
+ if (!setifcall(fd, callsign))
+ return 0;
+
+ /* Now set the encapsulation */
+ int v = 4;
+ if (ioctl(fd, SIOCSIFENCAP, &v) == -1) {
+ perror("SIOCSIFENCAP");
+ return 0;
+ }
+
+ /* ax25 ifaces should not really need to have an IP address assigned to */
+ if (!startiface(dev, mtu, allow_broadcast))
+ return 0;
+
+ return 1;
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..01b0f71
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,136 @@
+// Copyright 2018 Matthias P. Braendli
+// SPDX-License-Identifier: GPL-2.0-only
+extern crate libc;
+
+use std::fs::{OpenOptions, File};
+use std::ffi::{CStr, CString};
+use std::os::unix::io::AsRawFd;
+use std::thread;
+use std::net::TcpStream;
+use std::str::FromStr;
+use std::io::{Read, Write};
+
+extern {
+ fn kissattach(
+ callsign: * const libc::c_char,
+ speed: libc::int32_t,
+ mtu: libc::int32_t,
+ kttyname: * const libc::c_char,
+ allow_broadcast: libc::int32_t) -> libc::int32_t;
+}
+
+fn create_pts_pair() -> std::io::Result<File> {
+ let master_file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open("/dev/ptmx")?;
+
+ unsafe {
+ let master_fd = master_file.as_raw_fd();
+ if libc::grantpt(master_fd) == -1 {
+ return Err(std::io::Error::last_os_error());
+ }
+ if libc::unlockpt(master_fd) == -1 {
+ return Err(std::io::Error::last_os_error());
+ }
+ }
+
+ Ok(master_file)
+}
+
+fn usage() {
+ eprintln!("fldigi-kissattach");
+ eprintln!(" Usage:");
+ eprintln!(" fldigi-kissattach CALLSIGN-SSID FLDIGI_IP:FLDIGI_PORT MTU");
+ eprintln!("");
+ eprintln!(" Example:");
+ eprintln!(" fldigi-kissattach HB9EGM-1 127.0.0.1:7342 120");
+
+ std::process::exit(1);
+}
+
+fn main() {
+ let args : Vec<String> = std::env::args().collect();
+ if args.len() != 4 {
+ usage();
+ }
+
+ let callsign = args[1].clone();
+ let fldigi_connect = args[2].clone();
+ let mtu = i32::from_str(&args[3]).unwrap();
+ eprintln!("Creating PTY pair");
+
+ let mut master_file = match create_pts_pair() {
+ Ok(fd) => fd,
+ Err(e) => panic!("create_pts_pair failed: {}", e)
+ };
+
+ eprintln!("PTS master: {:?}", master_file);
+
+ let slavename;
+ unsafe {
+ slavename = libc::ptsname(master_file.as_raw_fd());
+ }
+
+ if slavename.is_null() {
+ panic!("Cannot get PTS slave name");
+ }
+ unsafe {
+ let slice = CStr::from_ptr(slavename);
+ eprintln!("PTS slave: {:?}", slice);
+ }
+
+
+ let callsign = CString::new(callsign).expect("Failed to convert callsign to CString");
+ let speed : i32 = 9600;
+ let allow_broadcast : i32 = 1;
+
+ let success = unsafe {
+ kissattach(
+ callsign.as_ptr(),
+ speed,
+ mtu,
+ slavename,
+ allow_broadcast)
+ };
+
+ if success == 0 {
+ panic!("kissattach failed");
+ }
+
+
+ let mut radio = TcpStream::connect(fldigi_connect).unwrap();
+
+ let mut pty_tx_side = master_file.try_clone()
+ .expect("Cannot clone PTY file");
+
+ let mut radio_tx = radio.try_clone().unwrap();
+
+ let writer = thread::spawn(move || {
+ loop {
+ // read from pty, write to fldigi
+
+ let mut buf = [0; 1024];
+ let num_bytes_rx = pty_tx_side.read(&mut buf).unwrap();
+
+ let txdata = &buf[0..num_bytes_rx];
+ radio_tx.write(txdata).unwrap();
+ }
+ });
+
+ loop {
+ // read from fldigi, write to master_file
+
+ let mut buf = [0; 1024];
+ let num_bytes_rx = radio.read(&mut buf).unwrap();
+
+ if num_bytes_rx == 0 {
+ break;
+ }
+
+ let txdata = &buf[0..num_bytes_rx];
+ master_file.write(txdata).unwrap();
+ }
+
+ writer.join().unwrap();
+}