Implemented automatic station ID

This commit is contained in:
Mark Qvist 2020-05-27 14:30:05 +02:00
parent 506d4659a1
commit f6e12426d0
3 changed files with 90 additions and 11 deletions

19
KISS.c
View File

@ -13,18 +13,21 @@ uint8_t frame_buffer[MAX_PAYLOAD];
uint8_t write_buffer[MAX_PAYLOAD*2+3];
extern bool verbose;
extern bool daemonize;
extern int attached_if;
extern int device_type;
extern void cleanup(void);
void kiss_frame_received(int frame_len) {
if (verbose) printf("Got KISS frame\r\n");
int written = write(attached_if, frame_buffer, frame_len);
if (written == -1) {
if (verbose) printf("Could not write received KISS frame to network interface, is the interface up?\r\n");
} else if (written != frame_len) {
printf("Error: Could only write %d of %d bytes to interface", written, frame_len);
cleanup();
exit(1);
if ( (device_type == IF_TUN && frame_len >= TUN_MIN_FRAME_SIZE) || (device_type == IF_TAP && frame_len >= ETHERNET_MIN_FRAME_SIZE) ) {
int written = write(attached_if, frame_buffer, frame_len);
if (written == -1) {
if (verbose && !daemonize) printf("Could not write received KISS frame (%d bytes) to network interface, is the interface up?\r\n", frame_len);
} else if (written != frame_len) {
if (!daemonize) printf("Error: Could only write %d of %d bytes to interface", written, frame_len);
cleanup();
exit(1);
}
}
}

View File

@ -38,6 +38,8 @@ Attach TNC devices as system network interfaces
-m, --mtu=MTU Specify interface MTU
-n, --noipv6 Filter IPv6 traffic from reaching TNC
--noup Only create interface, don't bring it up
-s, --id=CALLSIGN Station identification data
-t, --interval=SECONDS Maximum interval between station identifications
-v, --verbose Enable verbose output
-?, --help Give this help list
--usage Give a short usage message
@ -50,6 +52,8 @@ Additionally, it is worth noting that __tncattach__ can filter out IPv6 packets
If you intend to use __tncattach__ on a system with mDNS services enabled (avahi-daemon, for example), you may want to consider modifying your mDNS setup to exclude TNC interfaces, or turning it off entirely, since it will generate a lot of traffic that might be unwanted.
You can configure tncattach to automatically transmit station identification according to a given interval, by using the --id and --interval options. Identification will be transmitted as raw data frames with whatever content has been specified in the --id option. Useful for amateur radio use, or other areas where station identification is necessary. Identification beacons will be transmitted if the amount of time since the last identification is greater than the configured interval and there is any data to send. Channel capacity will therefore not be wasted on IDs for stations that are not actively transmitting.
## Examples
Create an ethernet device with a USB-connected TNC, set the MTU, filter IPv6 traffic, and set an IPv4 address:

View File

@ -5,6 +5,7 @@
#include <argp.h>
#include <syslog.h>
#include <sys/stat.h>
#include <time.h>
#include "Constants.h"
#include "Serial.h"
#include "KISS.h"
@ -38,6 +39,10 @@ char* netmask;
int mtu;
int device_type = IF_TUN;
char* id;
int id_interval = -1;
time_t last_id = 0;
void cleanup(void) {
close_port(attached_tnc);
close_tap(attached_if);
@ -149,6 +154,33 @@ void read_loop(void) {
if (if_len > 0) {
if (if_len >= min_frame_size) {
if (!noipv6 || (noipv6 && !is_ipv6(if_buffer))) {
if (id_interval != -1) {
time_t now = time(NULL);
if (now == -1) {
if (daemonize) {
syslog(LOG_ERR, "Could not get system time, exiting now");
} else {
printf("Error: Could not get system time, exiting now\r\n");
}
cleanup();
exit(1);
} else {
if (now > last_id + id_interval) {
int id_len = strlen(id);
if (verbose) {
if (!daemonize) {
printf("Transmitting %d bytes of identification data on %s: %s\r\n", id_len, if_name, id);
}
}
uint8_t* id_frame = malloc(strlen(id));
memcpy(id_frame, id, id_len);
kiss_write_frame(attached_tnc, id_frame, id_len);
last_id = now;
}
}
}
kiss_write_frame(attached_tnc, if_buffer, if_len);
}
}
@ -166,7 +198,6 @@ void read_loop(void) {
if (fdi == TNC_FD_INDEX) {
int tnc_len = read(attached_tnc, serial_buffer, sizeof(serial_buffer));
if (tnc_len > 0) {
if (verbose) printf("Data from TNC: %d bytes.\r\n", tnc_len);
for (int i = 0; i < tnc_len; i++) {
kiss_serial_read(serial_buffer[i]);
}
@ -192,9 +223,9 @@ void read_loop(void) {
exit(1);
}
const char *argp_program_version = "tncattach 0.1.2";
const char *argp_program_version = "tncattach 0.1.3";
const char *argp_program_bug_address = "<mark@unsigned.io>";
static char doc[] = "\r\nAttach TNC devices as system network interfaces\vAs an example, to attach the TNC connected to /dev/ttyUSB0 as a full ethernet device with an MTU of 576 bytes and assign an IPv4 address, use the following command:\r\n\r\n\ttncattach /dev/ttyUSB0 115200 -m 576 -e --ipv4 10.0.0.1/24\r\n\r\nTo create an interface that doesn't use ethernet, but transports IP directly, and filters IPv6 packets out, a command like the following can be used:\r\n\r\n\ttncattach /dev/ttyUSB0 115200 --noipv6 --ipv4 10.0.0.1/24";
static char doc[] = "\r\nAttach TNC devices as system network interfaces\vTo attach the TNC connected to /dev/ttyUSB0 as an ethernet device with an MTU of 512 bytes and assign an IPv4 address, while filtering IPv6 traffic, use:\r\n\r\n\ttncattach /dev/ttyUSB0 115200 -m 512 -e --noipv6 --ipv4 10.0.0.1/24\r\n\r\nStation identification can be performed automatically. Use the --id and --idinterval options. Identification beacons will be transmitted if the amount of time since the last identification is greater than the configured interval and there is any data to send. Channel capacity will therefore not be wasted on IDs for stations that are not actively transmitting.";
static char args_doc[] = "port baudrate";
static struct argp_option options[] = {
{ "mtu", 'm', "MTU", 0, "Specify interface MTU"},
@ -203,6 +234,8 @@ static struct argp_option options[] = {
{ "ipv4", 'i', "IP_ADDRESS", 0, "Configure an IPv4 address on interface"},
{ "noipv6", 'n', 0, 0, "Filter IPv6 traffic from reaching TNC"},
{ "noup", 1, 0, 0, "Only create interface, don't bring it up"},
{ "interval", 't', "SECONDS", 0, "Maximum interval between station identifications"},
{ "id", 's', "CALLSIGN", 0, "Station identification data"},
{ "verbose", 'v', 0, 0, "Enable verbose output"},
{ 0 }
};
@ -211,6 +244,9 @@ static struct argp_option options[] = {
struct arguments {
char *args[N_ARGS];
char *ipv4;
char *id;
bool valid_id;
int id_interval;
int baudrate;
int mtu;
bool tap;
@ -242,6 +278,24 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
}
break;
case 't':
arguments->id_interval = atoi(arg);
if (arguments->id_interval < 0) {
printf("Error: Invalid identification interval specified\r\n\r\n");
argp_usage(state);
}
break;
case 's':
arguments->id = arg;
if (strlen(arg) < 1 || strlen(arg) > arguments->mtu) {
printf("Error: Invalid identification string specified\r\n\r\n");
argp_usage(state);
} else {
arguments->valid_id = true;
}
break;
case 'i':
arguments->ipv4 = arg;
arguments->set_ipv4 = true;
@ -443,6 +497,8 @@ int main(int argc, char **argv) {
arguments.noipv6 = false;
arguments.daemon = false;
arguments.noup = false;
arguments.id_interval = -1;
arguments.valid_id = false;
argp_parse(&argp, argc, argv, 0, 0, &arguments);
arguments.baudrate = atoi(arguments.args[1]);
@ -456,6 +512,22 @@ int main(int argc, char **argv) {
if (arguments.noup) noup = true;
mtu = arguments.mtu;
if (arguments.id_interval >= 0) {
if (!arguments.valid_id) {
printf("Error: Periodic identification requested, but no valid indentification data specified\r\n");
cleanup();
exit(1);
} else {
id_interval = arguments.id_interval;
id = malloc(strlen(arguments.id));
strcpy(id, arguments.id);
}
} else if (arguments.valid_id && arguments.id_interval == -1) {
printf("Error: Periodic identification requested, but no indentification interval specified\r\n");
cleanup();
exit(1);
}
attached_if = open_tap();
attached_tnc = open_port(arguments.args[0]);
if (setup_port(attached_tnc, arguments.baudrate)) {