sobredirect/redirector.c

887 lines
23 KiB
C

/*
Copyright (C) 2006 AbsoluteValue Systems, Inc. All Rights Reserved.
Originally written and maintained by: Solomon Peachy <pizza@shaftnet.org>
Local redirection & Debugging code by: Mark Mathews <mark@linux-wlan.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
/* Basic over-the-wire serial packet */
struct s_msg {
u_int16_t magic;
u_int16_t flags;
u_int16_t seqnum_pkt;
u_int16_t seqnum_dat;
u_int16_t pktlen;
u_int8_t data[];
} __attribute__ ((packed));
#define SOB_MAGIC 0x0584
struct sob_config {
u_int32_t baud;
u_int32_t stopbits;
u_int32_t databits;
u_int8_t parity;
u_int8_t flow;
struct in_addr ip;
u_int16_t port;
} __attribute__ ((packed));
#define MSG_FLAG_BREAK 0x0001
#define MSG_FLAG_NONDATA 0x8000
#define MSG_FLAG_CONFIG 0x4000
#define SERIAL_ESC_CHAR 0xff
#define SERIAL_ESC_CHAR2 0x00
#define SERIAL_ESC_BREAK 0x00
#define MAX_PACKET_LEN 1470
#define BUF_LEN 4096
/* ================================================================ */
static void dump_config(char *prefix, struct sob_config *cfg)
{
syslog(LOG_INFO, "%s Far Host %s:%d Serial %d-%d%c%d Flow %c",
prefix,
inet_ntoa(cfg->ip), cfg->port,
cfg->baud, cfg->databits, cfg->parity, cfg->stopbits,
cfg->flow);
}
static void process_msg(struct s_msg *msg_in, struct in_addr *far_ip)
{
if (msg_in->flags & MSG_FLAG_CONFIG) {
struct sob_config *far_cfg = (struct sob_config *) msg_in->data;
far_cfg->baud = ntohl(far_cfg->baud);
far_cfg->stopbits = ntohl(far_cfg->stopbits);
far_cfg->databits = ntohl(far_cfg->databits);
far_cfg->port = ntohs(far_cfg->port);
syslog(LOG_INFO, "Rx Config from %s", inet_ntoa(*far_ip));
dump_config("Rx Config: ", far_cfg);
}
}
static void send_config(int far_sock, struct sob_config *far_cfg,
struct sockaddr_in *far_addr)
{
static u_int8_t pkt_buf[MAX_PACKET_LEN];
struct s_msg *msg_out = (struct s_msg *) pkt_buf;
int i;
msg_out->flags = MSG_FLAG_NONDATA | MSG_FLAG_CONFIG;
msg_out->seqnum_pkt = 0;
msg_out->pktlen = sizeof(*far_cfg);
msg_out->magic = SOB_MAGIC;
memcpy(msg_out->data, far_cfg, sizeof(*far_cfg));
far_cfg = (struct sob_config *) msg_out->data;
far_cfg->baud = htonl(far_cfg->baud);
far_cfg->stopbits = htonl(far_cfg->stopbits);
far_cfg->databits = htonl(far_cfg->databits);
far_cfg->port = htons(far_cfg->port);
msg_out->magic = htons(msg_out->magic);
msg_out->flags = htons(msg_out->flags);
msg_out->seqnum_pkt = htons(msg_out->seqnum_pkt);
msg_out->seqnum_dat = htons(msg_out->seqnum_dat);
msg_out->pktlen = htons(msg_out->pktlen);
i = sendto(far_sock, pkt_buf,
ntohs(msg_out->pktlen) + sizeof(struct s_msg),
MSG_DONTWAIT, (struct sockaddr*) far_addr, sizeof(*far_addr));
if (i < 0) {
syslog(LOG_ERR, "cfg sendto failed: %m");
}
}
void printhelp() {
fprintf(stderr, " Serial Over Broadband Redirector\n (c) AbsoluteValue Systems 2006\n\n");
fprintf(stderr, "\t-d <serialdev> -s <commsparams> -i <farhost> -p <farport>\n");
fprintf(stderr, "\t[ -b <min_buf_size> ] [ -t <max_buf_time> ]\n");
fprintf(stderr, "\t[ -1 <delimeter1> [ -2 <delimeter2> ] ]\n");
fprintf(stderr, "\t[ -x | -r ] [ -h ] [ -l ttl ] [ -L ] [ -D ]\n\n");
fprintf(stderr, "\t-h (this message)\n\n");
fprintf(stderr, "\t-x Enable XON/XOFF (software) flow control\n");
fprintf(stderr, "\t-r Enable RTS/CTS (hardware) flow control\n");
fprintf(stderr, "\t-D Run as a Daemon\n");
fprintf(stderr, "\t-L Enable modem control lines\n");
fprintf(stderr, "\t-t # Max time to wait for full buffer (in ms, default 250)\n");
fprintf(stderr, "\t-b # Min bytes to buffer (default 1)\n");
fprintf(stderr, "\t-l # TTL for multicast packets (default 1)\n\n");
fprintf(stderr, "commsparams: <baud>-<databits><parity><stopbits>\n");
fprintf(stderr, " examples include: 9600-8N1, 19200-6E2\n");
fprintf(stderr, "delimeters: Specified in hex, ie 0x20 or 0xfe\n");
fprintf(stderr, "\n");
}
static int run = 1;
int main (int argc, char **argv)
{
struct sob_config sob_cfg;
/* Basic communications parameters */
char *comm_params = NULL;
char delim1 = 0;
char delim2 = 0;
int delim1_enable = 0;
int delim2_enable = 0;
int modem_lines = 0;
int multicast = 0;
int hw_flow = 0;
int sw_flow = 0;
int min_buf_size = 1; /* bytes */
int max_buf_time = 1000; /* ms */
unsigned char mult_ttl = 1;
struct sockaddr_in far_addr;
struct sockaddr_in my_addr;
int far_sock;
char *ser_dev = NULL;
char *far_host = NULL;
int ser_fd;
struct termios ser_cfg;
int daemonize = 0;
int i;
memset(&far_addr, 0, sizeof(far_addr));
memset(&my_addr, 0, sizeof(my_addr));
far_addr.sin_family = AF_INET;
my_addr.sin_family = AF_INET;
/* Parse command line */
while(1) {
int c;
c = getopt(argc, argv, "hd:s:i:p:b:t:xrl:D1:2:L");
if (c == -1) break;
switch (c) {
case 'h':
printhelp();
exit(0);
case 'd':
ser_dev = optarg;
break;
case 's':
comm_params = optarg;
break;
case 'i':
far_host = optarg;
break;
case 'p':
sob_cfg.port = atoi(optarg);
break;
case 'b':
min_buf_size = atoi(optarg);
break;
case 't':
max_buf_time = atoi(optarg);
break;
case 'x':
sw_flow = 1;
break;
case 'r':
hw_flow = 1;
break;
case 'D':
daemonize = 1;
break;
case 'l':
mult_ttl = atoi(optarg);
break;
case 'L':
modem_lines = 1;
break;
case '1':
delim1 = strtol(optarg, NULL, 16);
delim1_enable = 1;
break;
case '2':
delim2 = strtol(optarg, NULL, 16);
delim2_enable = 1;
break;
default:
fprintf(stderr, "getopt returned bogus option '%c'\n", c);
return 1;
}
}
if (!ser_dev || !far_host || !sob_cfg.port || !comm_params) {
fprintf(stderr, "ERROR: missing command-line arguments.\n\n");
printhelp();
return 2;
}
if (hw_flow && sw_flow) {
fprintf(stderr, "ERROR: can't use both hardware and software flow control.\n\n");
printhelp();
return 10;
}
if (delim2_enable && !delim1_enable) {
fprintf(stderr, "ERROR: Can't specify delim2 without delim1\n\n");
return 11;
}
if (hw_flow)
sob_cfg.flow = 'H';
else if (sw_flow)
sob_cfg.flow = 'S';
else
sob_cfg.flow = 'N';
/* Parse hostname */
i = inet_aton(far_host, &far_addr.sin_addr);
if (!i) {
struct hostent *host;
host = gethostbyname(far_host);
if (!host) {
fprintf(stderr, "host lookup failed for '%s'\n",
far_host);
return 3;
}
memcpy(&far_addr.sin_addr.s_addr, host->h_addr, sizeof(far_addr.sin_addr.s_addr));
}
/* Find out if address is multicast */
{
unsigned long int addr = ntohl(far_addr.sin_addr.s_addr);
if ((addr >= 3758096384UL) && (addr < 4026531840UL)) {
multicast = 1;
}
}
memcpy(&sob_cfg.ip, &far_addr.sin_addr.s_addr, sizeof(sob_cfg.ip));
/* Parse serial parameters */
i = sscanf(comm_params, "%d-%d%c%d", &sob_cfg.baud, &sob_cfg.databits,
&sob_cfg.parity, &sob_cfg.stopbits);
if (i < 4) {
fprintf(stderr, "Invalid commparameters (%s)\n", comm_params);
printhelp();
return 6;
}
sob_cfg.parity &= ~0x20; /* Case insensitive */
/* Open socket, bind it. */
far_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (far_sock < 0) {
perror("Could not open socket");
return 4;
}
/* TTL */
if (multicast) {
struct ip_mreq mreq;
int flag = 0;
mreq.imr_multiaddr.s_addr = far_addr.sin_addr.s_addr;
mreq.imr_interface.s_addr = htonl( INADDR_ANY );
setsockopt(far_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
// my_addr.sin_addr = far_addr.sin_addr;
i = setsockopt(far_sock, IPPROTO_IP, IP_MULTICAST_TTL,
&mult_ttl, sizeof(mult_ttl));
if (i < 0) {
perror("Could not set TTL");
return 10;
}
i = setsockopt( far_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
&flag, sizeof(flag));
if(i < 0) {
perror("Could not turn off multicast loopback");
return 11;
}
}
/* Set non-block mode */
i = fcntl(far_sock, F_GETFL, 0);
if (i < 0) {
perror("Couldn't get fcntl");
return 11;
}
i |= O_NONBLOCK;
i = fcntl(far_sock, F_SETFL, i);
if (i < 0) {
perror("Couldn't set fcntl");
return 12;
}
far_addr.sin_port = htons(sob_cfg.port);
my_addr.sin_port = far_addr.sin_port;
i = bind(far_sock, (struct sockaddr *) &my_addr, sizeof(my_addr));
if (i < 0) {
perror("Could not bind socket to address");
return 9;
}
/* Open serial port */
ser_fd = open(ser_dev,O_RDWR|O_NONBLOCK|O_NOCTTY|O_ASYNC);
if (ser_fd < 0) {
perror("Could not open serial device");
return 5;
}
if (!isatty(ser_fd)) {
perror("Not a TTY\n");
return 999;
}
/* Set serial Parameters */
i = setserial(&ser_cfg, ser_fd, sob_cfg.baud, sob_cfg.databits,
sob_cfg.parity, sob_cfg.stopbits,
hw_flow, sw_flow, modem_lines);
if (i > 0) {
printhelp();
return 7;
}
if (i < 0) {
perror("Could not initialize serial device");
return 8;
}
/* Turn off Break */
i = ioctl(ser_fd, TIOCCBRK);
if (i < 0) {
perror("Could not turn off BREAK");
return 18;
}
/* Ignore sigpipes */
signal(SIGPIPE, SIG_IGN);
if (daemonize) daemon(0, 0);
/* And at this point, start! */
openlog("sob", LOG_PID, LOG_DAEMON);
/* Serial State */
int rx_delim = 0; // 0 == no, 1 == rx1, 2 == rx2
int rx_esc = 0; // 0 == no, 1 == yes, 2 == next is special.
int ser_brk = 0; /* Received a break on the serial port */
u_int16_t sequence_pkt_rx = 0;
u_int16_t sequence_pkt_tx = 0;
u_int16_t sequence_dat_rx = 0;
u_int16_t sequence_dat_tx = 0;
static u_int8_t pkt_buf[MAX_PACKET_LEN];
struct pollfd pfds[2];
static u_int8_t ser_out_buf[BUF_LEN];
u_int16_t ser_out_head = 0;
u_int16_t ser_out_tail = 0;
static u_int8_t net_out_buf[BUF_LEN];
u_int16_t net_out_head = 0;
u_int16_t net_out_tail = 0;
struct timeval last_rx_ser;
struct timeval last_rx_net;
/* Set up the poll */
pfds[0].fd = far_sock;
pfds[0].revents = 0;
pfds[0].events = POLLIN|POLLPRI;
pfds[1].fd = ser_fd;
pfds[1].revents = 0;
pfds[1].events = POLLIN|POLLPRI;
syslog(LOG_INFO, "sobredird bound and active");
dump_config("Local config: ", &sob_cfg);
send_config(far_sock, &sob_cfg, &far_addr);
#define TV_FLATTEN(__tv__) ((__tv__.tv_sec * 1000000) + __tv__.tv_usec)
/* Now we can run */
while (run) {
struct timeval now;
int64_t delta1, delta2;
u_int16_t len, len2;
/* Compute the actual time we need to sleep;
min of (max_buf_time, max_buf_time - (now-last_rx_net),
max_buf_time - (now-last_rx_ser) */
gettimeofday(&now, NULL);
delta1 = delta2 = 1000 * max_buf_time;
if (net_out_head - net_out_tail) {
delta1 += TV_FLATTEN(last_rx_ser) - TV_FLATTEN(now);
if (delta1 < 0) {
// fprintf(stderr, "pre time watermark, setting net out\n");
pfds[0].events |= POLLOUT;
delta1 = 0;
}
}
if (ser_out_head - ser_out_tail) {
delta2 += TV_FLATTEN(last_rx_net) - TV_FLATTEN(now);
if (delta2 < 0) {
pfds[1].events |= POLLOUT;
delta2 = 0;
}
}
pfds[0].revents = 0;
pfds[1].revents = 0;
i = poll(pfds, 2, min_t(int64_t, delta1, delta2) / 1000);
#if 0
{
// XXX this lets us get serial line twiddles:
// TIOCM_CD TIOCM_RI TIOCM_DSR TIOCM_CTS // TIOCM_DTR TIOCM_RTS
int val = 0, j = 0;
j = ioctl(ser_fd, TIOCMGET, &val);
if (j < 0) {
fprintf(stderr, "TIOCMGET failed %m\n");
} else {
fprintf(stderr, "mflag %d %#x\n", j, val);
}
}
#endif
/* If we got a BREAK signal, do the right thing. */
if (ser_brk && !(pfds[0].events & POLLOUT)) {
// fprintf(stderr, "ser_break, setting net out\n");
pfds[0].events |= POLLOUT;
continue;
}
gettimeofday(&now, NULL);
/* If the poll timed out, see if we hit a watermark point */
if (i == 0) {
delta1 = delta2 = 1000 * max_buf_time;
if (net_out_head - net_out_tail) {
delta1 += TV_FLATTEN(last_rx_ser) - TV_FLATTEN(now);
if (delta1 < 0) {
// fprintf(stderr, "pre time watermark, setting net out\n");
pfds[0].events |= POLLOUT;
}
}
if (ser_out_head - ser_out_tail) {
delta2 += TV_FLATTEN(last_rx_net) - TV_FLATTEN(now);
if (delta2 < 0) {
pfds[1].events |= POLLOUT;
}
}
/* And turn around immediately and re-poll */
continue;
}
/* Handle serial port reset */
if (pfds[1].revents & (POLLERR|POLLHUP|POLLNVAL)) {
syslog(LOG_ERR, "Serial port reset, purging buffers (%d)\n", pfds[1].revents);
tcflush(ser_fd, TCIOFLUSH);
close(ser_fd);
ser_fd = open(ser_dev,O_RDWR|O_NONBLOCK|O_NOCTTY|O_ASYNC);
ser_out_head = ser_out_tail = 0;
net_out_head = net_out_tail = 0;
if (ser_fd < 0) {
syslog(LOG_CRIT, "Could not open serial device, terminating: %m");
return 5;
}
i = tcsetattr(ser_fd, TCSANOW, &ser_cfg);
if (i < 0) {
syslog(LOG_CRIT, "Could not initialize serial device: %m");
}
pfds[1].fd = ser_fd;
continue;
}
/* Handle the serial port OUT */
if ((pfds[1].revents & POLLOUT) && (pfds[1].events & POLLOUT)) {
len = min_t(u_int16_t, BUF_LEN - (ser_out_tail % BUF_LEN),
ser_out_head - ser_out_tail);
i = write(ser_fd, &ser_out_buf[ser_out_tail % BUF_LEN], len);
if (i < 0) {
syslog(LOG_ERR, "write failed: %m");
} else {
ser_out_tail += i;
}
if (ser_out_head == ser_out_tail) {
pfds[1].events &= ~POLLOUT;
}
// fprintf(stdout, "ser out, %d bytes, ser_qlen %d\n", i, ser_out_head - ser_out_tail);
}
/* Handle the network socket OUT */
if ((pfds[0].revents & POLLOUT) && (pfds[0].events & POLLOUT)) {
struct s_msg *msg_out = (struct s_msg *) pkt_buf;
msg_out->magic = SOB_MAGIC;
msg_out->flags = 0;
msg_out->seqnum_pkt = sequence_pkt_tx++;
msg_out->pktlen = 0;
msg_out->seqnum_dat = sequence_dat_tx;
if (ser_brk) {
// fprintf(stderr, "BREAK, sending to far end\n");
msg_out->flags |= MSG_FLAG_BREAK;
ser_out_head = ser_out_tail = 0;
net_out_head = net_out_tail = 0;
tcflush(ser_fd, TCIOFLUSH);
ser_brk = 0;
}
/* Copy over to buffer; handle wraps! */
len = min_t(u_int16_t, BUF_LEN - (net_out_tail % BUF_LEN),
net_out_head - net_out_tail);
len = min_t(u_int16_t, len, MAX_PACKET_LEN - sizeof(struct s_msg));
memcpy(&msg_out->data[msg_out->pktlen],
&net_out_buf[net_out_tail % BUF_LEN], len);
net_out_tail += len;
msg_out->pktlen += len;
sequence_dat_tx += len;
/* Handle wrap */
len2 = min_t(u_int16_t, BUF_LEN - (net_out_tail % BUF_LEN),
net_out_head - net_out_tail);
len2 = min_t(u_int16_t, len2, MAX_PACKET_LEN - sizeof(struct s_msg) - msg_out->pktlen);
memcpy(&msg_out->data[msg_out->pktlen],
&net_out_buf[net_out_tail % BUF_LEN], len2);
net_out_tail += len2;
msg_out->pktlen += len2;
sequence_dat_tx += len2;
/* Byteswap and send */
msg_out->magic = htons(msg_out->magic);
msg_out->flags = htons(msg_out->flags);
msg_out->seqnum_pkt = htons(msg_out->seqnum_pkt);
msg_out->seqnum_dat = htons(msg_out->seqnum_dat);
msg_out->pktlen = htons(msg_out->pktlen);
i = sendto(far_sock, pkt_buf,
ntohs(msg_out->pktlen) + sizeof(struct s_msg),
MSG_DONTWAIT, (struct sockaddr*) &far_addr, sizeof(far_addr));
if (i < 0) {
syslog(LOG_ERR, "data sendto failed: %m");
}
/* Mark outbound Network to include OUT */
if ((net_out_head - net_out_tail) < min_buf_size) {
// fprintf(stderr, "clearing net out\n");
pfds[0].events &= ~POLLOUT;
}
// fprintf(stdout, "net out (%d bytes), net_qlen %d\n", ntohs(msg_out->pktlen), net_out_head - net_out_tail);
}
/* Handle the serial port IN */
if (pfds[1].revents & (POLLIN|POLLPRI)) {
// fprintf(stdout, "ser in\n");
u_int8_t c;
len = net_out_head - net_out_tail; /* size of data in buffer */
if (len >= BUF_LEN) {
syslog(LOG_ERR, "Rx Serial Buffer Full... (%d bytes)", net_out_head - net_out_tail);
continue;
}
len = BUF_LEN - len;
while ((len > 0) && ((i = read(ser_fd, &c, sizeof(c))) > 0)) {
last_rx_ser = now;
switch (rx_esc) {
case 0:
if (c == SERIAL_ESC_CHAR) {
/* Don't pass up */
rx_esc++;
continue;
} else {
/* Normal data */
net_out_buf[net_out_head++ % BUF_LEN] = c;
len--;
}
break;
case 1:
/* SERIAL_ESC_CHAR 0x?? */
if (c == SERIAL_ESC_CHAR) {
/* This is an escaped SERIAL_ESC_CHAR! */
net_out_buf[net_out_head++ % BUF_LEN] = c;
len--;
rx_esc = 0;
} else if (c == SERIAL_ESC_CHAR2) {
/* Don't pass up */
rx_esc++;
}
break;
case 2:
/* SERIAL_ESC_CHAR SERIAL_ESC_CHAR2 0x?? */
if (c == SERIAL_ESC_BREAK) {
/* Break! */
ser_brk++;
rx_esc = 0;
syslog(LOG_INFO, "Rx serial break!\n");
continue;
} else {
/* All others are parity errors, ignore */
continue;
}
break;
default:
rx_esc = 0;
// ERROR.
break;
}
/* If we got here, the character was legit data */
// Check for and handle delimeter detection
switch (rx_delim) {
case 0:
if (delim1_enable && (c == delim1))
rx_delim++;
else
rx_delim = 0;
break;
case 1:
if (delim2_enable && (c == delim2))
rx_delim++;
else
rx_delim = 0;
break;
default:
rx_delim = 0;
// ERROR;
break;
}
if ((delim1_enable && !delim2_enable && (rx_delim == 1)) ||
(delim1_enable && delim2_enable && (rx_delim == 2))) {
pfds[0].events |= POLLOUT;
rx_delim = 0;
}
}
/* Merk outbound network to include OUT */
if ((net_out_head - net_out_tail) >= min_buf_size) {
// fprintf(stderr, "marking net out\n");
pfds[0].events |= POLLOUT;
}
// fprintf(stdout, "ser in, net_qlen %d\n", net_out_head - net_out_tail);
}
/* Handle the network socket IN */
if (pfds[0].revents & (POLLIN|POLLPRI)) { /* Read from Network */
struct sockaddr_in remote_addr;
struct s_msg *msg_in = (struct s_msg *) pkt_buf;
socklen_t socklen = sizeof(remote_addr);
i = recvfrom(far_sock, pkt_buf, MAX_PACKET_LEN, MSG_DONTWAIT,
(struct sockaddr*) &remote_addr, &socklen);
// fprintf(stdout, "net in len %d\n", i);
last_rx_net = now;
if (i < 0) {
perror("recvfrom failed");
} else if (i < sizeof(struct s_msg)) {
syslog(LOG_WARNING, "Short read! (%d bytes)\n", i);
} else {
if (!multicast && (remote_addr.sin_addr.s_addr != far_addr.sin_addr.s_addr)) {
syslog(LOG_INFO, "discarding pkt from non-configured host");
continue;
}
msg_in->magic = ntohs(msg_in->magic);
msg_in->flags = ntohs(msg_in->flags);
msg_in->seqnum_pkt = ntohs(msg_in->seqnum_pkt);
msg_in->pktlen = ntohs(msg_in->pktlen);
msg_in->seqnum_dat = htons(msg_in->seqnum_dat);
if (msg_in->magic != SOB_MAGIC) {
syslog(LOG_INFO, "discarding pkt w/o magic");
continue;
}
if (msg_in->pktlen > MAX_PACKET_LEN) {
syslog(LOG_INFO, "discarding pktlen %d > maxlen", msg_in->pktlen);
continue;
}
if (msg_in->flags & MSG_FLAG_NONDATA) {
process_msg(msg_in, &remote_addr.sin_addr);
continue;
}
/* Packet Sequence number validation */
if (!multicast && sequence_pkt_rx) {
if (msg_in->seqnum_pkt <= sequence_pkt_rx) {
if ((msg_in->seqnum_pkt == 0) &&
((msg_in->seqnum_pkt - sequence_pkt_rx) > 1)) {
syslog(LOG_INFO, "pkt sequence reset (was %d)", sequence_pkt_rx);
} else {
syslog(LOG_WARNING, "pkt sequence %d replay (curr %d)\n", msg_in->seqnum_pkt, sequence_pkt_rx);
// continue;
}
}
if ((msg_in->seqnum_pkt - sequence_pkt_rx) > 1) {
syslog(LOG_WARNING, "pkt sequence gap of %d packets!\n", msg_in->seqnum_pkt - sequence_pkt_rx - 1);
}
}
/* Data sequence number validation */
if (!multicast && sequence_dat_rx) {
if (msg_in->seqnum_dat < sequence_dat_rx) {
if ((msg_in->seqnum_dat == 0) &&
((msg_in->seqnum_dat - sequence_dat_rx) > 1)) {
syslog(LOG_INFO, "data sequence reset (was %d)", sequence_dat_rx);
} else {
syslog(LOG_WARNING, "data sequence %d replay (curr %d)\n", msg_in->seqnum_dat, sequence_dat_rx);
// continue;
}
}
if (msg_in->seqnum_dat > sequence_dat_rx) {
syslog(LOG_WARNING, "data sequence gap of %d bytes!\n", msg_in->seqnum_dat - sequence_dat_rx);
}
}
/* Update Sequence counters */
sequence_pkt_rx = msg_in->seqnum_pkt;
sequence_dat_rx = msg_in->seqnum_dat + msg_in->pktlen;
if ((i - sizeof(struct s_msg)) < msg_in->pktlen) {
syslog(LOG_WARNING, "Short read! (%d vs %d bytes) truncating\n", msg_in->pktlen, (int) (i - sizeof(struct s_msg)));
msg_in->pktlen = i - sizeof(struct s_msg);
}
if ((ser_out_head - ser_out_tail) >= BUF_LEN) {
syslog(LOG_WARNING, "Network Rx Buffer Full (seq_dat %d, seq_pkt %d, buflen %d, discarding %d bytes)\n",
msg_in->seqnum_dat,
msg_in->seqnum_pkt,
ser_out_head - ser_out_tail,
msg_in->pktlen);
pfds[1].events |= POLLOUT;
continue;
}
/* Copy over to buffer; handle wraps */
len = min_t(u_int16_t, BUF_LEN - (ser_out_head % BUF_LEN),
BUF_LEN - (ser_out_head - ser_out_tail));
len = min_t(u_int16_t, len, msg_in->pktlen);
memcpy(&ser_out_buf[ser_out_head % BUF_LEN], msg_in->data, len);
ser_out_head += len;
/* Handle wrap */
len2 = min_t(u_int16_t, BUF_LEN - (ser_out_head % BUF_LEN),
BUF_LEN - (ser_out_head - ser_out_tail));
len2 = min_t(u_int16_t, len2, msg_in->pktlen - len);
memcpy(&ser_out_buf[ser_out_head % BUF_LEN], msg_in->data + len, len2);
ser_out_head += len2;
if ((len + len2) < msg_in->pktlen) {
syslog(LOG_WARNING, "Network Rx Buffer Overflow (lost %d bytes)!\n",
msg_in->pktlen - (len + len2));
}
/* Mark outbound serial to include OUT */
if (ser_out_head != ser_out_tail) {
pfds[1].events |= POLLOUT;
}
/* If we get a break */
if (msg_in->flags & MSG_FLAG_BREAK) {
/* Reset our buffers */
ser_out_head = ser_out_tail = 0;
net_out_head = net_out_tail = 0;
tcflush(ser_fd, TCIOFLUSH);
syslog(LOG_INFO, "sending break to serial port\n");
tcsendbreak(ser_fd, 0);
}
}
// fprintf(stdout, "ser_qlen %d\n", ser_out_head - ser_out_tail);
}
}
/* Clean up */
syslog(LOG_INFO, "sobredird shutting down");
tcflush(ser_fd, TCIOFLUSH);
close(ser_fd);
close(far_sock);
closelog();
return 0;
}