uronode/axdigi.c

307 lines
7.1 KiB
C

/*
* axdigi: Cross and straight port digipeater program
* Copyright (C) 1995 Craig Small VK2XLZ
* modificatioins 2012-present Brian N1URO
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* JSN - Small tweaks to ensure compilation and execution under Linux 2.1.x.
* 12th June 1997.
*
* Thanks to Helmut Grohne for a minor patch
*
*/
#include <net/if.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
/* below added by N1URO */
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <signal.h>
#include <linux/ax25.h>
/* added by N1URO */
#include <netax25/daemon.h>
#include "node.h"
int recv_packet(unsigned char *buf, int size, unsigned char *port);
void print_call(unsigned char *buf);
unsigned char *find_call(char *port);
void add_port(char *call, char *port);
void get_interfaces(int skt);
/*
* The defines we use
*/
#define AXALEN 7
#define E_BIT 0x01 /* Address extension bit */
#define REPEATED 0x80 /* Has-been-repeated bit */
#define MAX_PORTS 16
// #define VERSION "0.3"
#define AXDIGI_PID_FILE "/var/run/axdigi.pid"
int port_count = 0;
unsigned char portname[MAX_PORTS][20];
unsigned char portcall[MAX_PORTS][8];
void(*sigterm_defhnd)(int);
void quit_handler(int sig)
{
unlink(AXDIGI_PID_FILE);
signal(SIGTERM, SIG_IGN);
fprintf(stderr, "axDigi quitting.\n\r");
signal(SIGTERM, sigterm_defhnd);
raise(SIGTERM);
return;
}
void hup_handler(int sig)
{
signal(SIGHUP, SIG_IGN);
fprintf(stderr, "SIGHUP caught by axDigi.\n\r");
signal(SIGHUP, hup_handler); /* Restore hangup handler */
}
int main(int argc, char *argv[])
{
int skt;
int size, rt;
unsigned char buf[4096];
struct sockaddr sa;
int asize;
FILE *pidfile;
/* Check our huge range of flags */
if (argc > 1)
{
if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "-h") ==0)
{
printf("axdigi: version %s.\n\r", VERSION);
printf("Copywrite (c) 1995 Craig Small - VK2XLZ\n\r");
printf("modificatiions Copyright (C) 2012-present by Brian N1URO\n\n");
printf("axdigi comes with ABSOLUTELY NO WARRANTY.\n\r");
printf("This is free software, and you are welcome to redistribute it\n\r");
printf("under the terms of GNU General Public Licence as published\n\r");
printf("by Free Software Foundation; either version 2 of the License, or\n\r");
printf("(at your option) any later version.\n\r");
return 0;
}
}
/* Routine to daemonize - added by N1URO */
if (!daemon_start(TRUE)) {
fprintf(stderr, "Sorry, axdigi cannot become a daemon\n");
return 1;
}
/* Change to keep code more modern - N1URO */
if ((skt = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_AX25))) == -1)
{
perror("socket");
return(1);
}
pidfile = fopen(AXDIGI_PID_FILE, "w");
fprintf(pidfile, "%d\n", (int)getpid());
fprintf(stderr, "axDigi started. \n");
fclose(pidfile);
signal(SIGHUP, hup_handler);
sigterm_defhnd = signal(SIGTERM, quit_handler);
get_interfaces(skt);
while(1)
{
asize = sizeof(sa);
if ((size = recvfrom(skt, buf, sizeof(buf), 0, &sa, &asize)) == -1)
{
perror("recv");
exit(1);
}
if ((rt = recv_packet(buf, size, sa.sa_data)) >= 0)
{
if (rt < port_count)
{
asize = sizeof(sa);
strcpy(sa.sa_data, portname[rt]);
if (sendto(skt, buf, size, 0, &sa, asize) == -1)
perror("sendto");
continue;
}
/* printf("Unknown port %s\n", sa.sa_data);*/
} /* recv_packet true */
} /* while(1) */
close(skt);
}
int recv_packet(unsigned char *buf, int size, unsigned char *port)
{
unsigned char *bptr;
int count, i;
unsigned char *call;
/* printf("Got packet size %d\n", size);*/
/*
* Decode the AX.25 Packet
*/
/* Find packet, skip over flag */
bptr = buf+1;
/* Now at destination address */
/* print_call(bptr);
printf("<-");*/
bptr += AXALEN;
/* Now at source address */
/* print_call(bptr);*/
if (bptr[6] & E_BIT)
{
/* printf("\n");*/
return -1; /* No digis, we're not interested */
}
/* printf(" ");*/
bptr += AXALEN;
/* Now at digipeaters */
count = 0;
while( count < AX25_MAX_DIGIS && ( (bptr - buf) < size))
{
/* print_call(bptr);
printf(", ");*/
if (bptr[6] & REPEATED)
{
/* This one has been repeated, move to next one */
bptr += AXALEN;
count++;
continue;
}
/* Check to see if callsign is one of ours */
for (i = 0; i < port_count; i++)
{
/* printf("compare ");
print_call(bptr);
printf(" ");
print_call(portcall[i]);
printf("\n");*/
if ( (bcmp(bptr, portcall[i], AXALEN-1) == 0) && ((bptr[6] & 0x1e) == portcall[i][6]))
{
/* Copy new address over and turn on repeated bit*/
call = find_call(port);
if (call == NULL)
return -1;
bcopy(call, bptr, AXALEN-1);
bptr[6] = (bptr[6] & ~0x1e) | call[6];
bptr[6] |= REPEATED;
return i;
}
} /* for */
return -1;
}
return -1;
}
void print_call(unsigned char *bptr)
{
printf("%c%c%c%c%c%c-%d", bptr[0] >> 1, bptr[1] >> 1,
bptr[2] >> 1, bptr[3] >> 1, bptr[4] >> 1, bptr[5] >> 1,
(bptr[6] >> 1) & 0xf);
}
void add_port(char *call, char *port)
{
unsigned char *s;
int n;
if (port_count == MAX_PORTS)
return;
s = portcall[port_count];
while( (*call != '-') && ( (int)(s - portcall[port_count])< 6))
*s++ = (*call++) << 1;
call++; /* skip over dash */
n = atoi(call);
*s = n << 1;
strcpy(portname[port_count], port);
port_count++;
}
unsigned char *find_call(char *port)
{
static unsigned char callsign[8];
int i;
for(i = 0; i < port_count; i++)
{
if (strcmp(port, portname[i]) == 0)
{
bcopy(portcall[i], callsign, 7);
return callsign;
}
}
return (char*)NULL;
}
void get_interfaces(int skt)
{
char buf[1024];
struct ifconf ifc;
struct ifreq *ifr;
int i;
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(skt, SIOCGIFCONF, &ifc) < 0)
{
perror("ioctl");
exit(1);
}
ifr = ifc.ifc_req;
for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
{
if (ioctl(skt, SIOCGIFHWADDR, ifr) < 0)
continue;
if (ifr->ifr_hwaddr.sa_family == AF_AX25)
{
/* AX25 port, add to list */
if (port_count < MAX_PORTS)
{
bcopy(ifr->ifr_hwaddr.sa_data, portcall[port_count], 7);
strcpy(portname[port_count], ifr->ifr_name);
port_count++;
}
}
} /* for */
}
void(*sigterm_defhnd)(int);