This project is a collection of former (and some new) projects connected together to make an APRS digipeater, which doubles as an APRS weather station, with PE1RXF telemetry server capabilities.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
8.3 KiB

10 months ago
#include "TAP.h"
char tap_name[IFNAMSIZ];
extern bool verbose;
extern bool noipv6;
extern bool set_ipv4;
extern bool set_netmask;
extern bool noup;
extern int mtu;
extern int device_type;
extern char if_name[IFNAMSIZ];
extern char* ipv4_addr;
extern char* netmask;
extern void cleanup();
int open_tap(void) {
struct ifreq ifr;
int fd = open("/dev/net/tun", O_RDWR);
if (fd < 0) {
perror("Could not open clone device");
exit(1);
} else {
memset(&ifr, 0, sizeof(ifr));
// TODO: Enable PI header again?
if (device_type == IF_TAP) {
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
} else if (device_type == IF_TUN) {
ifr.ifr_flags = IFF_TUN;
} else {
printf("Error: Unsupported interface type\r\n");
cleanup();
exit(1);
}
strcpy(tap_name, "tnc%d");
strncpy(ifr.ifr_name, tap_name, IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
perror("Could not configure network interface");
exit(1);
} else {
strcpy(if_name, ifr.ifr_name);
int inet = socket(AF_INET, SOCK_DGRAM, 0);
if (inet == -1) {
perror("Could not open AF_INET socket");
cleanup();
exit(1);
} else {
if (ioctl(inet, SIOCGIFMTU, &ifr) < 0) {
perror("Could not get interface flags from kernel");
close(inet);
cleanup();
exit(1);
} else {
ifr.ifr_mtu = mtu;
if (ioctl(inet, SIOCSIFMTU, &ifr) < 0) {
perror("Could not configure interface MTU");
close(inet);
cleanup();
exit(1);
}
// Configure TX queue length
if (ioctl(inet, SIOCGIFTXQLEN, &ifr) < 0) {
perror("Could not get interface flags from kernel");
close(inet);
cleanup();
exit(1);
} else {
ifr.ifr_qlen = TXQUEUELEN;
if (ioctl(inet, SIOCSIFTXQLEN, &ifr) < 0) {
perror("Could not set interface TX queue length");
close(inet);
cleanup();
exit(1);
}
}
// Configure ARP characteristics
char path_buf[256];
if (device_type == IF_TAP) {
snprintf(path_buf, sizeof(path_buf), "/proc/sys/net/ipv4/neigh/%s/base_reachable_time_ms", ifr.ifr_name);
int arp_fd = open(path_buf, O_WRONLY);
if (arp_fd < 0) {
perror("Could not open proc entry for ARP parameters");
close(inet);
cleanup();
exit(1);
} else {
if (dprintf(arp_fd, "%d", ARP_BASE_REACHABLE_TIME*1000) <= 0) {
perror("Could not configure interface ARP parameter base_reachable_time_ms");
close(inet);
close(arp_fd);
cleanup();
exit(1);
} else {
close(arp_fd);
}
}
snprintf(path_buf, sizeof(path_buf), "/proc/sys/net/ipv4/neigh/%s/retrans_time_ms", ifr.ifr_name);
arp_fd = open(path_buf, O_WRONLY);
if (arp_fd < 0) {
perror("Could not open proc entry for ARP parameters");
close(inet);
cleanup();
exit(1);
} else {
if (dprintf(arp_fd, "%d", ARP_RETRANS_TIME*1000) <= 0) {
perror("Could not configure interface ARP parameter retrans_time_ms");
close(inet);
close(arp_fd);
cleanup();
exit(1);
} else {
close(arp_fd);
}
}
}
// Bring up if requested
if (!noup) {
if (ioctl(inet, SIOCGIFFLAGS, &ifr) < 0) {
perror("Could not get interface flags from kernel");
close(inet);
cleanup();
exit(1);
} else {
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (ioctl(inet, SIOCSIFFLAGS, &ifr) < 0) {
perror("Could not bring up interface");
close(inet);
cleanup();
exit(1);
} else {
if (set_ipv4) {
struct ifreq a_ifr;
struct sockaddr_in addr, snm;
memset(&a_ifr, 0, sizeof(a_ifr));
memset(&addr, 0, sizeof(addr));
memset(&snm, 0, sizeof(addr));
strncpy(a_ifr.ifr_name, ifr.ifr_name, IFNAMSIZ);
addr.sin_family = AF_INET;
snm.sin_family = AF_INET;
int addr_conversion = inet_pton(AF_INET, ipv4_addr, &(addr.sin_addr));
if (addr_conversion != 1) {
printf("Error: Invalid IPv4 address specified\r\n");
close(inet);
cleanup();
exit(1);
} else {
a_ifr.ifr_addr = *(struct sockaddr*)&addr;
if (ioctl(inet, SIOCSIFADDR, &a_ifr) < 0) {
perror("Could not set IP-address");
close(inet);
cleanup();
exit(1);
} else {
if (set_netmask) {
int snm_conversion = inet_pton(AF_INET, netmask, &(snm.sin_addr));
if (snm_conversion != 1) {
printf("Error: Invalid subnet mask specified\r\n");
close(inet);
cleanup();
exit(1);
} else {
a_ifr.ifr_addr = *(struct sockaddr*)&snm;
if (ioctl(inet, SIOCSIFNETMASK, &a_ifr) < 0) {
perror("Could not set subnet mask");
close(inet);
cleanup();
exit(1);
}
}
}
}
}
}
}
}
}
}
}
return fd;
}
}
}
int close_tap(int tap_fd) {
return close(tap_fd);
}