diff --git a/.gitignore b/.gitignore index c6127b3..f1f206d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +tncattach # Prerequisites *.d diff --git a/KISS.c b/KISS.c new file mode 100644 index 0000000..d948afc --- /dev/null +++ b/KISS.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "KISS.h" +#include "Serial.h" + +int frame_len; +bool IN_FRAME; +bool ESCAPE; + +uint8_t kiss_command = CMD_UNKNOWN; +uint8_t frame_buffer[MAX_PAYLOAD]; +uint8_t write_buffer[MAX_PAYLOAD*2+3]; + +void kiss_frame_received(int frame_len) { + +} + +void kiss_serial_read(uint8_t sbyte) { + if (IN_FRAME && sbyte == FEND && kiss_command == CMD_DATA) { + IN_FRAME = false; + kiss_frame_received(frame_len); + } else if (sbyte == FEND) { + IN_FRAME = true; + kiss_command = CMD_UNKNOWN; + frame_len = 0; + } else if (IN_FRAME && frame_len < MAX_PAYLOAD) { + // Have a look at the command byte first + if (frame_len == 0 && kiss_command == CMD_UNKNOWN) { + // Strip of port nibble + kiss_command = sbyte & 0x0F; + } else if (kiss_command == CMD_DATA) { + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + + if (frame_len < MAX_PAYLOAD) { + frame_buffer[frame_len++] = sbyte; + } + } + } + } +} + +int kiss_write_frame(int serial_port, uint8_t* buffer, int frame_len) { + int write_len = 0; + write_buffer[write_len++] = FEND; + write_buffer[write_len++] = CMD_DATA; + for (int i = 0; i < frame_len; i++) { + uint8_t byte = buffer[i]; + if (byte == FEND) { + write_buffer[write_len++] = FESC; + write_buffer[write_len++] = TFEND; + } else if (byte == FESC) { + write_buffer[write_len++] = FESC; + write_buffer[write_len++] = TFESC; + } else { + write_buffer[write_len++] = byte; + } + } + write_buffer[write_len++] = FEND; + + return write(serial_port, write_buffer, write_len); +} \ No newline at end of file diff --git a/KISS.h b/KISS.h index ea31251..556388f 100644 --- a/KISS.h +++ b/KISS.h @@ -10,4 +10,9 @@ #define CMD_SLOTTIME 0x03 #define CMD_TXTAIL 0x04 #define CMD_FULLDUPLEX 0x05 -#define CMD_SETHARDWARE 0x06 \ No newline at end of file +#define CMD_SETHARDWARE 0x06 + +#define MAX_PAYLOAD 1522 + +void kiss_serial_read(uint8_t sbyte); +int kiss_write_frame(int serial_port, uint8_t* buffer, int frame_len); \ No newline at end of file diff --git a/README.md b/README.md index e69de29..46a08b8 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +TNC Attach +========== +Attach KISS TNC devices as network interfaces in Linux and macOS. \ No newline at end of file diff --git a/Serial.c b/Serial.c new file mode 100644 index 0000000..2b882e8 --- /dev/null +++ b/Serial.c @@ -0,0 +1,168 @@ +#include "Serial.h" + +int open_port(char* port) { + int fd; + fd = open(port, O_RDWR | O_NOCTTY | O_SYNC | O_NDELAY); + + if (fd == -1) { + perror("The serial port could not be opened"); + } else { + fcntl(fd, F_SETFL, 0); + } + + return fd; +} + +int close_port(int fd) { + return close(fd); +} + +void set_speed(void *tty_s, int speed) { + cfsetospeed(tty_s, speed); + cfsetispeed(tty_s, speed); +} + +bool setup_port(int fd, int speed) { + struct termios tty; + if (tcgetattr(fd, &tty) != 0) { + perror("Error setting port speed, could not read port parameters"); + return false; + } + + switch (speed) { + case 0: + set_speed(&tty, B0); + break; + case 50: + set_speed(&tty, B50); + break; + case 75: + set_speed(&tty, B75); + break; + case 110: + set_speed(&tty, B110); + break; + case 134: + set_speed(&tty, B134); + break; + case 150: + set_speed(&tty, B150); + break; + case 200: + set_speed(&tty, B200); + break; + case 300: + set_speed(&tty, B300); + break; + case 600: + set_speed(&tty, B600); + break; + case 1200: + set_speed(&tty, B1200); + break; + case 2400: + set_speed(&tty, B2400); + break; + case 4800: + set_speed(&tty, B4800); + break; + case 9600: + set_speed(&tty, B9600); + break; + case 19200: + set_speed(&tty, B19200); + break; + case 38400: + set_speed(&tty, B38400); + break; + case 57600: + set_speed(&tty, B57600); + break; + case 115200: + set_speed(&tty, B115200); + break; + case 230400: + set_speed(&tty, B230400); + break; + default: + printf("Error: Invalid port speed %d specified", speed); + return false; + } + + // Set 8-bit characters, no parity, one stop bit + tty.c_cflag |= CS8; + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + + // Disable hardware flow control + tty.c_cflag &= ~CRTSCTS; + + // Enable reading and ignore modem + // control lines + tty.c_cflag |= CREAD | CLOCAL; + + // Disable canonical mode, echo + // and signal characters. + tty.c_lflag &= ~ICANON; + tty.c_lflag &= ~ECHO; + tty.c_lflag &= ~ECHOE; + tty.c_lflag &= ~ECHONL; + tty.c_lflag &= ~ISIG; + + // Disable processing of input, + // just pass the raw data. + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); + + // Disable XON/XOFF software flow control. + tty.c_iflag &= ~(IXON | IXOFF | IXANY); + + // Disable processing output bytes + // and new line conversions + tty.c_oflag &= ~OPOST; + tty.c_oflag &= ~ONLCR; + + // Block forever until at least one byte is read. + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + // TODO: Check these + // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX) + // tty.c_oflag &= ~OXTABS; + // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX) + // tty.c_oflag &= ~ONOEOT; + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + perror("Could not configure serial port parameters"); + return false; + } else { + return true; + } +} + +bool set_port_blocking(int fd, bool should_block) { + struct termios tty; + memset(&tty, 0, sizeof tty); + + if (tcgetattr(fd, &tty) != 0) { + perror("Error configuring port blocking behaviour, could not read port parameters"); + return false; + } else { + // TODO: Implement this correctly + if (should_block) { + // Block forever until at least one byte is read. + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + } else { + // Never block, always return immediately with + // whatever is available. + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 0; + } + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + perror("Could not set port parameters while configuring blocking behaviour"); + return false; + } else { + return true; + } + } +} \ No newline at end of file diff --git a/Serial.h b/Serial.h new file mode 100644 index 0000000..84f0d39 --- /dev/null +++ b/Serial.h @@ -0,0 +1,12 @@ +#include +#include +#include +#include +#include +#include +#include + +int open_port(char* port); +int close_port(int fd); +bool setup_port(int fs, int speed); +bool set_port_blocking(int fd, bool should_block); \ No newline at end of file diff --git a/TAP.c b/TAP.c new file mode 100644 index 0000000..acdf302 --- /dev/null +++ b/TAP.c @@ -0,0 +1,3 @@ +#include "TAP.h" + +char tap_name[IFNAMSIZ]; \ No newline at end of file diff --git a/TAP.h b/TAP.h new file mode 100644 index 0000000..e69de29 diff --git a/makefile b/makefile index 3db1134..5ff4f30 100644 --- a/makefile +++ b/makefile @@ -1,10 +1,11 @@ .DEFAULT_GOAL := all -.PHONY: all clean install +.PHONY: all clean install tncattach compiler = gcc flags = -lm all: tncattach +rebuild: clean all clean: @echo "Cleaning tncattach build..." @@ -13,7 +14,7 @@ clean: tncattach: @echo "Making tncattach..." @echo "Compiling with: ${compiler}" - ${compiler} ${flags} tncattach.c -o tncattach + ${compiler} ${flags} tncattach.c Serial.c KISS.c TAP.c -o tncattach -Wall install: all @echo "Installing tncattach..." \ No newline at end of file diff --git a/tncattach.c b/tncattach.c index 52c0875..e0e6ad2 100644 --- a/tncattach.c +++ b/tncattach.c @@ -1,5 +1,45 @@ +#include +#include +#include +#include "Serial.h" #include "KISS.h" +#include "TAP.h" + +#define SERIAL_BUFFER_SIZE 512 + +int attached_port; +uint8_t serial_buffer[512]; + +void signal_handler(int signal) { + printf("\r\nClosing serial port...\r\n"); + close_port(attached_port); + exit(0); +} + +void read_loop(tnc) { + bool should_continue = true; + while (should_continue) { + int len = read(attached_port, serial_buffer, sizeof(serial_buffer)); + if (len > 0) { + for (int i = 0; i < len; i++) { + kiss_serial_read(serial_buffer[i]); + } + } else { + printf("Error: Could not read from serial port, exiting now\r\n"); + close_port(attached_port); + exit(1); + } + } +} int main() { + signal(SIGINT, signal_handler); + + attached_port = open_port("/dev/tty.usbserial-"); + if (setup_port(attached_port, 115200)) { + printf("Port open\r\n"); + read_loop(attached_port); + } + return 0; } \ No newline at end of file