spdxl/src/udphub.c

1298 wiersze
34 KiB
C

/*
* dxlAPRS toolchain
*
* Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#define X2C_int32
#define X2C_index32
#ifndef X2C_H_
#include "X2C.h"
#endif
#define udphub_C_
#ifndef osi_H_
#include "osi.h"
#endif
#include <osic.h>
#ifndef udp_H_
#include "udp.h"
#endif
#ifndef aprsstr_H_
#include "aprsstr.h"
#endif
#ifndef Select_H_
#include "Select.h"
#endif
/* axudp bidirectional digi - user hub by OE5DXL */
#define udphub_CALLLEN 7
#define udphub_MAXLEN 338
#define udphub_MINLEN 17
static uint32_t udphub_POLYNOM = 0x8408UL;
static uint32_t udphub_CRCINIT = 0xFFFFUL;
#define udphub_SOURCECALL 7
#define udphub_DESTCALL 0
#define udphub_MAXFD 31
#define udphub_cCOM "#"
#define udphub_cSPOOF "p"
#define udphub_cBCIN "b"
#define udphub_cBCOUT "B"
#define udphub_cSENDALL "A"
#define udphub_LF "\012"
#define udphub_TICKER 15
typedef char RAWCALL[7];
struct TIMEVAL {
int32_t tvsec;
int32_t tvusec;
};
struct USER;
typedef struct USER * pUSER;
struct USER {
pUSER next;
RAWCALL call;
uint32_t uip;
uint32_t dport;
char datagot; /* not send same data twice to same ip/port */
char bcin; /* broadcast in accept */
char bcout; /* broadcast out allowed */
char willall; /* like host send all to */
char nopurge; /* entry from file no purge */
char nospoof; /* not overwrite ip:port */
uint32_t htime;
};
static uint8_t CRCL[256];
static uint8_t CRCH[256];
static char noinf;
static char modified;
static char peertopeer;
static char defaultbcout;
/* no broadcast send to new users */
static char defaultbcin;
static char show;
/* no broadcast accept for new users */
static char checkdigiip;
static pUSER users;
static uint32_t alllifetime;
static uint32_t systime;
/* time for all/unknown ssid */
static uint32_t lifetime;
static uint32_t touserport;
static uint32_t todigiport;
static uint32_t digiip;
static int32_t digisock;
static int32_t usersock;
static uint32_t maxentries;
static char initfn[1025];
static char wrfn[1025];
static RAWCALL broadcastdest;
/*
PROCEDURE ["C"] / select(n: INTEGER; readfds: ADDRESS; writefds: ADDRESS;
exceptfds: ADDRESS; timeout: ADDRESS) : INTEGER;
*/
static void Err(const char text[], uint32_t text_len)
{
osi_WrStr("udphub: ", 9ul);
osi_WrStr(text, text_len);
osi_WrStrLn(" error abort", 13ul);
X2C_ABORT();
} /* end Err() */
#define udphub_POLINOM 0x8408
static void Gencrctab(void)
{
uint32_t c;
uint32_t crc;
uint32_t i;
for (c = 0UL; c<=255UL; c++) {
crc = 255UL-c;
for (i = 0UL; i<=7UL; i++) {
if ((crc&1)) crc = (uint32_t)((uint32_t)(crc>>1)^0x8408UL);
else crc = crc>>1;
} /* end for */
CRCL[c] = (uint8_t)crc;
CRCH[c] = (uint8_t)(255UL-(crc>>8));
} /* end for */
} /* end Gencrctab() */
static void WCh(char c)
{
if (c!='\015') {
if ((uint8_t)c<' ' || (uint8_t)c>='\177') osi_WrStr(".", 2ul);
else osi_WrStr((char *) &c, 1u/1u);
}
} /* end WCh() */
static void ShowCall(char f[], uint32_t f_len, uint32_t pos)
{
uint32_t e;
uint32_t i;
uint32_t tmp;
char tmp0;
e = pos;
tmp = pos+5UL;
i = pos;
if (i<=tmp) for (;; i++) {
if (f[i]!='@') e = i;
if (i==tmp) break;
} /* end for */
tmp = e;
i = pos;
if (i<=tmp) for (;; i++) {
WCh((char)((uint32_t)(uint8_t)f[i]>>1));
if (i==tmp) break;
} /* end for */
i = (uint32_t)(uint8_t)f[pos+6UL]>>1&15UL;
if (i) {
osi_WrStr("-", 2ul);
if (i>=10UL) {
osi_WrStr((char *)(tmp0 = (char)(i/10UL+48UL),&tmp0),
1u/1u);
}
osi_WrStr((char *)(tmp0 = (char)(i%10UL+48UL),&tmp0), 1u/1u);
}
} /* end ShowCall() */
static uint32_t udphub_UA = 0x63UL;
static uint32_t udphub_DM = 0xFUL;
static uint32_t udphub_SABM = 0x2FUL;
static uint32_t udphub_DISC = 0x43UL;
static uint32_t udphub_FRMR = 0x87UL;
static uint32_t udphub_UI = 0x3UL;
static uint32_t udphub_RR = 0x1UL;
static uint32_t udphub_REJ = 0x9UL;
static uint32_t udphub_RNR = 0x5UL;
static void Showctl(uint32_t com, uint32_t cmd)
{
uint32_t cm;
char PF[4];
char tmp;
osi_WrStr(" ctl ", 6ul);
cm = (uint32_t)cmd&~0x10UL;
if ((cm&0xFUL)==0x1UL) {
osi_WrStr("RR", 3ul);
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
}
else if ((cm&0xFUL)==0x5UL) {
osi_WrStr("RNR", 4ul);
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
}
else if ((cm&0xFUL)==0x9UL) {
osi_WrStr("REJ", 4ul);
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
}
else if ((cm&0x1UL)==0UL) {
osi_WrStr("I", 2ul);
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>5)),&tmp), 1u/1u);
osi_WrStr((char *)(tmp = (char)(48UL+(cmd>>1&7UL)),&tmp),
1u/1u);
}
else if (cm==0x3UL) osi_WrStr("UI", 3ul);
else if (cm==0xFUL) osi_WrStr("DM", 3ul);
else if (cm==0x2FUL) osi_WrStr("SABM", 5ul);
else if (cm==0x43UL) osi_WrStr("DISC", 5ul);
else if (cm==0x63UL) osi_WrStr("UA", 3ul);
else if (cm==0x87UL) osi_WrStr("FRMR", 5ul);
else osi_WrHex(cmd, 1UL);
strncpy(PF,"v^-+",4u);
if (com==0UL || com==3UL) osi_WrStr("v1", 3ul);
else {
osi_WrStr((char *) &PF[(com&1UL)+2UL*(uint32_t)
((0x10UL & (uint32_t)cmd)!=0)], 1u/1u);
}
} /* end Showctl() */
static void ShowFrame(char f[], uint32_t f_len, uint32_t len,
char noinfo)
{
uint32_t i;
char d;
char v;
i = 0UL;
while (!((uint32_t)(uint8_t)f[i]&1)) {
++i;
if (i>len) return;
}
/* no address end mark found */
if (i%7UL!=6UL) return;
/* address end not modulo 7 error */
osi_WrStr(" fm ", 5ul);
ShowCall(f, f_len, 7UL);
osi_WrStr(" to ", 5ul);
ShowCall(f, f_len, 0UL);
i = 14UL;
v = 1;
while (i+6UL<len && !((uint32_t)(uint8_t)f[i-1UL]&1)) {
if (v) {
osi_WrStr(" via", 5ul);
v = 0;
}
osi_WrStr(" ", 2ul);
ShowCall(f, f_len, i);
if ((uint32_t)(uint8_t)f[i+6UL]>=128UL && (((uint32_t)(uint8_t)
f[i+6UL]&1) || (uint32_t)(uint8_t)f[i+13UL]<128UL)) {
osi_WrStr("*", 2ul);
}
i += 7UL;
}
Showctl((uint32_t)((0x80U & (uint8_t)(uint8_t)f[6UL])!=0)
+2UL*(uint32_t)((0x80U & (uint8_t)(uint8_t)f[13UL])!=0)
, (uint32_t)(uint8_t)f[i]);
++i;
if (i<len) {
osi_WrStr(" pid ", 6ul);
osi_WrHex((uint32_t)(uint8_t)f[i], 1UL);
}
++i;
osic_WrLn();
if (!noinfo) {
d = 0;
while (i<len) {
if (f[i]!='\015') {
WCh(f[i]);
d = 1;
}
else if (d) {
osic_WrLn();
d = 0;
}
++i;
}
if (d) osic_WrLn();
}
} /* end ShowFrame() */
static char testCRC(char frame[], uint32_t frame_len,
int32_t size)
{
uint8_t h;
uint8_t l;
uint8_t b;
int32_t i;
int32_t tmp;
l = 0U;
h = 0U;
tmp = size-3L;
i = 0L;
if (i<=tmp) for (;; i++) {
b = (uint8_t)((uint8_t)(uint8_t)frame[i]^l);
l = CRCL[b]^h;
h = CRCH[b];
if (i==tmp) break;
} /* end for */
return frame[size-2L]==(char)l && frame[size-1L]==(char)h;
} /* end testCRC() */
/*
PROCEDURE GetIp1(h:ARRAY OF CHAR; VAR ip:IPNUM; VAR dp:UDPPORT):INTEGER;
CONST PORTSEP=":";
DEFAULTIP=7F000001H;
VAR i, p, n:CARDINAL;
ok:BOOLEAN;
BEGIN
p:=0;
h[HIGH(h)]:=0C;
ip:=0;
FOR i:=0 TO 4 DO
IF (i>=3) OR (h[0]<>PORTSEP) THEN
n:=0;
ok:=FALSE;
WHILE (h[p]>="0") & (h[p]<="9") DO
ok:=TRUE;
n:=n*10+ORD(h[p])-ORD("0");
INC(p);
END;
IF NOT ok THEN RETURN -1 END;
END;
IF i<3 THEN
IF h[0]<>PORTSEP THEN
IF (h[p]<>".") OR (n>255) THEN RETURN -1 END;
ip:=ip*256+n;
END;
ELSIF i=3 THEN
IF h[0]<>PORTSEP THEN
ip:=ip*256+n;
IF (h[p]<>PORTSEP) OR (n>255) THEN RETURN -1 END;
ELSE p:=0; ip:=DEFAULTIP END;
ELSIF n>65535 THEN RETURN -1 END;
dp:=n;
INC(p);
END;
RETURN 0
END GetIp1;
*/
static int32_t GetIp1(char h[], uint32_t h_len, uint32_t * ip,
uint32_t * port)
{
uint32_t p;
uint32_t n;
uint32_t i;
char ok0;
int32_t GetIp1_ret;
X2C_PCOPY((void **)&h,h_len);
p = 0UL;
h[h_len-1] = 0;
*ip = 0UL;
for (i = 0UL; i<=4UL; i++) {
n = 0UL;
ok0 = 0;
while ((uint8_t)h[p]>='0' && (uint8_t)h[p]<='9') {
ok0 = 1;
n = (n*10UL+(uint32_t)(uint8_t)h[p])-48UL;
++p;
}
if (!ok0) {
GetIp1_ret = -1L;
goto label;
}
if (i<3UL) {
if (h[p]!='.' || n>255UL) {
GetIp1_ret = -1L;
goto label;
}
*ip = *ip*256UL+n;
}
else if (i==3UL) {
*ip = *ip*256UL+n;
if (h[p]!=':' || n>255UL) {
GetIp1_ret = -1L;
goto label;
}
}
else if (n>65535UL) {
GetIp1_ret = -1L;
goto label;
}
*port = n;
++p;
} /* end for */
GetIp1_ret = 0L;
label:;
X2C_PFREE(h);
return GetIp1_ret;
} /* end GetIp1() */
static int32_t getudp(int32_t fd, char buf[], uint32_t buf_len,
uint32_t * fromip0, uint32_t * fromport,
char checkip)
{
uint32_t ip;
int32_t len;
len = udpreceive(fd, buf, (int32_t)(buf_len), fromport, &ip);
if (len<2L || !testCRC(buf, buf_len, len)) {
if (show) osi_WrStrLn(" axudp crc error ", 18ul);
return -1L;
}
if (checkip && *fromip0!=ip) return -2L;
*fromip0 = ip;
return len;
} /* end getudp() */
static char Call2Str(const char r[], uint32_t r_len,
char t[], uint32_t t_len, uint32_t pos,
uint32_t * len)
{
uint32_t ssid;
uint32_t e;
uint32_t i;
char c;
uint32_t tmp;
e = pos;
tmp = pos+5UL;
i = pos;
if (i<=tmp) for (;; i++) {
if (r[i]!='@') e = i;
if (i==tmp) break;
} /* end for */
tmp = e;
i = pos;
if (i<=tmp) for (;; i++) {
c = (char)((uint32_t)(uint8_t)r[i]>>1);
if ((uint8_t)c<=' ') {
t[*len] = 0;
*len = 0UL;
return 0;
}
t[*len] = c;
++*len;
if (i==tmp) break;
} /* end for */
ssid = (uint32_t)(uint8_t)r[pos+6UL]>>1&15UL;
if (ssid>0UL) {
t[*len] = '-';
++*len;
if (ssid>9UL) {
t[*len] = '1';
++*len;
}
t[*len] = (char)(ssid%10UL+48UL);
++*len;
}
return 1;
} /* end Call2Str() */
#define udphub_SSID "-"
static char Str2Call(char s[], uint32_t s_len, uint32_t * i,
uint32_t p, char cb[], uint32_t cb_len)
{
uint32_t j;
char Str2Call_ret;
X2C_PCOPY((void **)&s,s_len);
j = p;
while ((*i<=s_len-1 && (uint8_t)s[*i]>' ') && s[*i]!='-') {
if (j<p+6UL) {
cb[j] = (char)((uint32_t)(uint8_t)s[*i]*2UL);
++j;
}
++*i;
}
while (j<p+6UL) {
cb[j] = '@';
++j;
}
j = 0UL;
if (s[*i]=='-') {
++*i;
j = 16UL;
if ((uint8_t)s[*i]>='0' && (uint8_t)s[*i]<='9') {
j = (uint32_t)(uint8_t)s[*i]-48UL;
++*i;
}
if ((uint8_t)s[*i]>='0' && (uint8_t)s[*i]<='9') {
j = (j*10UL+(uint32_t)(uint8_t)s[*i])-48UL;
++*i;
}
}
cb[p+6UL] = (char)(j*2UL+1UL); /* ssid */
Str2Call_ret = j<=15UL;
X2C_PFREE(s);
return Str2Call_ret;
} /* end Str2Call() */
static int32_t GetIp(char h[], uint32_t h_len, uint32_t * ip,
uint32_t * dp, uint32_t * lp, int32_t * fd,
char * check)
{
int32_t GetIp_ret;
X2C_PCOPY((void **)&h,h_len);
if (aprsstr_GetIp2(h, h_len, ip, dp, lp, check)<0L) {
GetIp_ret = -1L;
goto label;
}
*fd = openudp();
if (*fd<0L || bindudp(*fd, *lp)<0L) {
/*OR (udp.udpnonblock(fd)<0)*/
GetIp_ret = -1L;
goto label;
}
GetIp_ret = 0L;
label:;
X2C_PFREE(h);
return GetIp_ret;
} /* end GetIp() */
static char GetNum(const char h[], uint32_t h_len,
uint32_t * n)
{
uint32_t i;
*n = 0UL;
i = 0UL;
while ((uint8_t)h[i]>='0' && (uint8_t)h[i]<='9') {
*n = ( *n*10UL+(uint32_t)(uint8_t)h[i])-48UL;
++i;
}
return h[i]==0;
} /* end GetNum() */
static void parms(void)
{
char err0;
char h[1024];
uint32_t i;
uint32_t fromdigiport;
err0 = 0;
for (;;) {
osi_NextArg(h, 1024ul);
if (h[0U]==0) break;
if ((h[0U]=='-' && h[1U]) && h[2U]==0) {
if (h[1U]=='l') {
osi_NextArg(h, 1024ul);
if (!GetNum(h, 1024ul, &i)) Err("-l minutes", 11ul);
lifetime = i*60UL;
}
else if (h[1U]=='L') {
osi_NextArg(h, 1024ul);
if (!GetNum(h, 1024ul, &i)) Err("-L minutes", 11ul);
alllifetime = i*60UL;
}
else if (h[1U]=='a') peertopeer = 1;
else if (h[1U]=='I') defaultbcin = 1;
else if (h[1U]=='O') defaultbcout = 1;
else if (h[1U]=='b') {
osi_NextArg(h, 1024ul);
if (h[0U]==0) Err("-b call", 8ul);
i = 0UL;
if (!Str2Call(h, 1024ul, &i, 0UL, broadcastdest, 7ul)) {
Err("-b wrong SSID", 14ul);
}
}
else if (h[1U]=='i') {
/* init filename */
osi_NextArg(initfn, 1025ul);
}
else if (h[1U]=='w') {
/* write table filename */
osi_NextArg(wrfn, 1025ul);
}
else if (h[1U]=='m') {
osi_NextArg(h, 1024ul);
if (!GetNum(h, 1024ul, &maxentries)) Err("-m number", 10ul);
}
else if (h[1U]=='p') {
osi_NextArg(h, 1024ul);
if (!GetNum(h, 1024ul, &touserport)) Err("-p portnumber", 14ul);
}
else if (h[1U]=='u') {
osi_NextArg(h, 1024ul);
if (GetIp(h, 1024ul, &digiip, &todigiport, &fromdigiport,
&digisock, &checkdigiip)<0L) {
Err("cannot open digi udp socket", 28ul);
}
}
else if (h[1U]=='v') show = 1;
else if (h[1U]=='V') {
show = 1;
noinf = 0;
}
else {
if (h[1U]=='h') {
osic_WrLn();
osi_WrStrLn(" -a route user-to-\
digi AND user-to-user", 71ul);
osi_WrStrLn(" -b <call> broadcast dest\
ination call", 62ul);
osi_WrStrLn(" -h this", 40ul);
osi_WrStrLn(" -I for new user: \
broadcast INPUT on", 68ul);
osi_WrStrLn(" -i <file> init routes fr\
om file", 57ul);
osi_WrStrLn(" -L <time> minutes route \
to all ssid\'s (default 10 min)", 80ul);
osi_WrStrLn(" 0 no all ssid \
routing", 57ul);
osi_WrStrLn(" -l <time> minutes lifeti\
me (default 1 week)", 69ul);
osi_WrStrLn(" -m <maxentries> else delete ol\
d entries (default 1000)", 74ul);
osi_WrStrLn(" -O for new user: \
broadcast OUTPUT on", 69ul);
osi_WrStrLn(" -p <userport> udp port for u\
sers", 54ul);
osi_WrStrLn(" -u <x.x.x.x:destport:listenport> axudp to digi \
/listenport check ip", 70ul);
osi_WrStrLn(" -v verbous",
43ul);
osi_WrStrLn(" -V verbous + fram\
es with Text", 62ul);
osi_WrStrLn(" -w <file> write user tab\
le to file (only if new entries and max. every 15s)", 101ul);
osic_WrLn();
osi_WrStrLn("Initfile:", 10ul);
osi_WrStrLn("NOCALL-15 192.168.0.1:4711 #comment", 36ul);
osi_WrStrLn("NOCALL-15 p 192.168.0.1:4711 #protected entry",
46ul);
osi_WrStrLn("#comment", 9ul);
osi_WrStrLn("NOCALL-15 p 0.0.0.0:0 no data to this call except\
to digi port", 63ul);
osi_WrStrLn("b enable broadcast input", 25ul);
osi_WrStrLn("B enable broadcast output", 26ul);
osi_WrStrLn("A send all frames", 18ul);
osic_WrLn();
osi_WrStrLn("Routing Table:", 15ul);
osi_WrStrLn("(-l) time old table entries will be purged except\
those from init file", 71ul);
osic_WrLn();
osi_WrStrLn("Source: AX.25 Source Call makes table entry with \
call/ip/sourceport/date", 73ul);
osi_WrStrLn(" Exception: Protected entry updates Date o\
nly", 53ul);
osic_WrLn();
osi_WrStrLn("Destinationcall: (call used for routing)", 41ul);
osi_WrStrLn(" First Digi with no H-bit, if not present, ax25 \
destination call is used", 74ul);
osic_WrLn();
osi_WrStrLn("Broadcast: if user enabled to input broadcast and\
ax25-destination equals broadcast call", 89ul);
osic_WrLn();
osi_WrStrLn("Destination: axudp ip/port", 27ul);
osic_WrLn();
osi_WrStrLn("Routing: frame will be sent to if", 34ul);
osi_WrStrLn(" user enabled to get all data", 31ul);
osi_WrStrLn(" OR broadcast and user enabled to get broadcast",
49ul);
osi_WrStrLn(" OR destinationcall with ssid equals user",
43ul);
osi_WrStrLn(" OR destinationcall with ssid fits to no user in\
table", 56ul);
osi_WrStrLn(" but destinationcall without ssid equals user\
seen since -L time", 69ul);
osi_WrStrLn(" exception 1: data never sent (back) to ip/port \
where came from", 65ul);
osi_WrStrLn(" exception 2: data sent only one time to ip/port\
even if more destinationcalls share same ip/port", 99ul);
osi_WrStrLn(" exception 3: with not \'-a\' only data from dig\
i port routes to destinationcall", 80ul);
osic_WrLn();
X2C_ABORT();
}
err0 = 1;
}
}
else {
/*
h[0]:=0C;
*/
err0 = 1;
}
if (err0) break;
}
if (err0) {
osi_WrStr(">", 2ul);
osi_WrStr(h, 1024ul);
osi_WrStrLn("< use -h", 9ul);
X2C_ABORT();
}
} /* end parms() */
static void ip2str(uint32_t ip, uint32_t port, char s[],
uint32_t s_len)
{
char h[21];
s[0UL] = 0;
aprsstr_IntToStr((int32_t)(ip/16777216UL), 1UL, h, 21ul);
aprsstr_Append(s, s_len, h, 21ul);
aprsstr_Append(s, s_len, ".", 2ul);
aprsstr_IntToStr((int32_t)(ip/65536UL&255UL), 1UL, h, 21ul);
aprsstr_Append(s, s_len, h, 21ul);
aprsstr_Append(s, s_len, ".", 2ul);
aprsstr_IntToStr((int32_t)(ip/256UL&255UL), 1UL, h, 21ul);
aprsstr_Append(s, s_len, h, 21ul);
aprsstr_Append(s, s_len, ".", 2ul);
aprsstr_IntToStr((int32_t)(ip&255UL), 1UL, h, 21ul);
aprsstr_Append(s, s_len, h, 21ul);
aprsstr_Append(s, s_len, ":", 2ul);
aprsstr_IntToStr((int32_t)port, 1UL, h, 21ul);
aprsstr_Append(s, s_len, h, 21ul);
} /* end ip2str() */
static void showpip(uint32_t ip, uint32_t port)
{
char h[51];
ip2str(ip, port, h, 51ul);
osi_WrStr(h, 51ul);
} /* end showpip() */
static void showcall(const char b[], uint32_t b_len, uint32_t start)
{
char h[16];
uint32_t l;
l = 0UL;
if (Call2Str(b, b_len, h, 16ul, start, &l)) {
h[l] = 0;
osi_WrStr(h, 16ul);
}
} /* end showcall() */
static void listtab(char fn[], uint32_t fn_len)
{
int32_t fd;
pUSER u;
char s[201];
char h[201];
uint32_t j;
uint32_t i;
X2C_PCOPY((void **)&fn,fn_len);
fd = osi_OpenWrite(fn, fn_len);
if (osic_FdValid(fd)) {
u = users;
while (u) {
i = 0UL;
if (Call2Str(u->call, 7ul, h, 201ul, 0UL, &i)) {
while (i<10UL) {
h[i] = ' ';
++i;
}
h[i] = 0;
}
else h[0U] = 0;
j = 0UL;
if (u->nospoof) {
aprsstr_Append(h, 201ul, "p", 2ul);
++j;
}
else if (u->nopurge) {
aprsstr_Append(h, 201ul, "f", 2ul);
++j;
}
if (u->bcout) {
aprsstr_Append(h, 201ul, "B", 2ul);
++j;
}
if (u->bcin) {
aprsstr_Append(h, 201ul, "b", 2ul);
++j;
}
if (u->willall) {
aprsstr_Append(h, 201ul, "A", 2ul);
++j;
}
while (j<4UL) {
aprsstr_Append(h, 201ul, " ", 2ul);
++j;
}
ip2str(u->uip, u->dport, s, 201ul);
aprsstr_Append(h, 201ul, s, 201ul);
if (u->htime>0UL) {
i = aprsstr_Length(h, 201ul);
while (i<36UL) {
h[i] = ' ';
++i;
}
h[i] = 0;
aprsstr_DateToStr(u->htime, s, 201ul);
aprsstr_Append(h, 201ul, s, 201ul);
}
aprsstr_Append(h, 201ul, "\012", 2ul);
osi_WrBin(fd, (char *)h, 201u/1u, aprsstr_Length(h, 201ul));
u = u->next;
}
strncpy(h,"f from init file, \012p ip/port protected\012B BC out\012b B\
C in\012A gets all\012",201u);
osi_WrBin(fd, (char *)h, 201u/1u, aprsstr_Length(h, 201ul));
if (peertopeer) {
strncpy(h,"peer-to-peer routing on\012",201u);
osi_WrBin(fd, (char *)h, 201u/1u, aprsstr_Length(h, 201ul));
}
i = 0UL;
if (Call2Str(broadcastdest, 7ul, h, 201ul, 0UL, &i)) {
h[i] = 0;
aprsstr_Append(h, 201ul, " broadcast destination\012", 24ul);
osi_WrBin(fd, (char *)h, 201u/1u, aprsstr_Length(h, 201ul));
}
aprsstr_IntToStr((int32_t)touserport, 0UL, h, 201ul);
aprsstr_Append(h, 201ul, " user UDP port\012", 16ul);
osi_WrBin(fd, (char *)h, 201u/1u, aprsstr_Length(h, 201ul));
osic_Close(fd);
}
else Err("-w File Create", 15ul);
X2C_PFREE(fn);
} /* end listtab() */
static char cmpcall(const RAWCALL c, const char b[],
uint32_t b_len, uint32_t start, char withssid)
{
uint32_t i;
for (i = 0UL; i<=5UL; i++) {
if (c[i]!=b[i+start]) return 0;
} /* end for */
return !withssid || ((uint32_t)(uint8_t)c[6U]/2UL&15UL)==((uint32_t)
(uint8_t)b[start+6UL]/2UL&15UL);
} /* end cmpcall() */
static pUSER Realloc(char alloc)
{
uint32_t cnt;
pUSER new0;
pUSER last;
pUSER u;
cnt = 0UL;
last = 0;
new0 = 0;
u = users;
while (u) {
if (!u->nopurge && (u->htime+lifetime<systime || cnt>=maxentries)) {
/* old or too much entries */
if (last==0) users = u->next;
else last->next = u->next;
if (show) {
osi_WrStr("Purge User ", 12ul);
showcall(u->call, 7ul, 0UL);
osic_WrLn();
}
if (alloc && new0==0) new0 = u;
else osic_free((char * *) &u, sizeof(struct USER));
if (last==0) u = users;
else u = last->next;
modified = 1;
}
else {
last = u;
u = u->next;
++cnt;
}
}
if (alloc && new0==0) {
osic_alloc((char * *) &new0, sizeof(struct USER));
}
/* IF show THEN WrStr(" Table entries="); WrInt(cnt, 1); WrLn; END; */
return new0;
} /* end Realloc() */
static void showu(uint32_t dp, pUSER u)
{
if (u->nospoof) osi_WrStr(" writeprotected", 16ul);
if (u->bcout) osi_WrStr(" bc-out", 8ul);
if (u->bcin) osi_WrStr(" bc-in", 7ul);
if (u->willall) osi_WrStr(" gets-all", 10ul);
osi_WrStr(" IP:", 5ul);
showpip(u->uip, dp);
osic_WrLn();
} /* end showu() */
static void AddIp(uint32_t ip, uint32_t dp, char fix,
char nspoof, char * hasbcin,
char defbcin, char defbcout,
char getsall, const char buf[],
uint32_t buf_len)
{
pUSER last;
uint32_t i;
pUSER u;
/* for fast find, rechain to first position */
struct USER * anonym;
struct USER * anonym0;
*hasbcin = 0;
if (!((uint32_t)(uint8_t)buf[13UL]&1) && (uint8_t)
buf[20UL]>=(uint8_t)'\200') return;
/* via digi, store only direct heard */
u = users;
last = 0;
while (u) {
if (cmpcall(u->call, buf, buf_len, 7UL, 1)) {
if (last) {
last->next = u->next;
u->next = users;
users = u;
}
{ /* with */
struct USER * anonym = u;
anonym->htime = systime;
*hasbcin = anonym->bcin;
if (!anonym->nospoof) {
anonym->uip = ip; /* store if ip changed */
anonym->dport = dp;
}
}
/*
IF show THEN
WrStr("Found User "); showcall(buf, SOURCECALL);
showu(u);
END;
*/
return;
}
last = u;
u = u->next;
}
if (u==0) {
u = Realloc(1);
if (u==0) {
if (show) osi_WrStrLn(" user add out of memory", 24ul);
}
else {
{ /* with */
struct USER * anonym0 = u;
for (i = 0UL; i<=6UL; i++) {
anonym0->call[i] = buf[7UL+i];
} /* end for */
anonym0->call[6U] = (char)(((uint32_t)(uint8_t)
anonym0->call[6U]/2UL&15UL)*2UL); /* extract pure ssid */
anonym0->uip = ip;
anonym0->dport = dp;
anonym0->htime = systime;
anonym0->nospoof = nspoof;
anonym0->nopurge = fix;
anonym0->bcin = defbcin;
anonym0->bcout = defbcout;
anonym0->willall = getsall;
}
*hasbcin = defbcin;
if (show) {
osi_WrStr("Add User ", 10ul);
showcall(buf, buf_len, 7UL);
showu(dp, u);
}
u->next = users;
users = u;
}
}
} /* end AddIp() */
static char sendtouser(char ubuf0[], uint32_t ubuf_len,
int32_t blen0, char fromdigi, char bcin,
uint32_t fromip0, uint32_t fromport)
{
pUSER uu;
pUSER u;
pUSER exactu;
int32_t ci;
int32_t res0;
char ok0;
char broadcast;
char topeer;
ok0 = 0;
ci = 7L;
if (((uint32_t)(uint8_t)ubuf0[13UL]&1)) ci = 0L;
else {
/* find first not done via */
for (;;) {
ci += 7L;
if (ci>63L || ci+7L>=blen0) return 0;
/* no valid frame */
if ((uint8_t)ubuf0[ci+6L]<(uint8_t)'\200') break;
if (((uint32_t)(uint8_t)ubuf0[ci+6L]&1)) {
ci = 0L; /* all h-bits set */
break;
}
}
}
/*WrInt(ci, 1); WrStrLn(" =ci"); */
broadcast = (((fromdigi || bcin) && ci==0L) && broadcastdest[0U])
&& cmpcall(broadcastdest, ubuf0, ubuf_len, 0UL, 1);
topeer = !broadcast && (peertopeer || fromdigi); /* data for an user */
if (topeer) {
exactu = users;
while (exactu && !cmpcall(exactu->call, ubuf0, ubuf_len,
(uint32_t)ci, 1)) {
/* conpare with ssid */
exactu = exactu->next; /* find call + ssid match */
}
}
else exactu = 0;
/*WrInt(ORD(exactu<>NIL), 1); WrStrLn(" =exactu"); */
u = users;
while (u) {
u->datagot = 0;
if ((u->dport>0UL && ((fromdigi || fromip0!=u->uip)
|| fromport!=u->dport)) && (((u->willall || u==exactu)
|| broadcast && u->bcout) || (topeer && exactu==0)
&& cmpcall(u->call, ubuf0, ubuf_len, (uint32_t)ci, 0))) {
/* user enabled */
/* send never same way back */
/* try all same call without ssid match */
uu = users;
while (uu!=u && ((!uu->datagot || uu->uip!=u->uip)
|| uu->dport!=u->dport)) uu = uu->next;
if (uu==u) {
/* have not sent jet to ip/port */
u->datagot = 1;
res0 = udpsend(usersock, ubuf0, blen0, u->dport, u->uip);
if (show) {
osi_WrStr("< send to user ", 16ul);
showcall(u->call, 7ul, 0UL);
osi_WrStr(" ", 2ul);
showpip(u->uip, u->dport);
osi_WrStrLn("", 1ul);
}
if (u==exactu || broadcast) ok0 = 1;
}
}
/*
ELSE
showcall(u^.call, 0); WrStrLn(" sendno");
WrInt(ORD(u=exactu), 1); WrStr(" =u=exactu ");
showpip(u^.uip, u^.dport); WrStr(" =userip ");
showpip(fromip, fromport); WrStr(" =fromip ");
*/
u = u->next;
}
/* IF show & ok THEN WrStrLn("") END; */
return ok0;
} /* end sendtouser() */
static void err(char h[], uint32_t h_len, char fn[],
uint32_t fn_len, uint32_t lc)
{
char s[4001];
X2C_PCOPY((void **)&h,h_len);
X2C_PCOPY((void **)&fn,fn_len);
osi_WrStr("Error in line ", 15ul);
aprsstr_IntToStr((int32_t)lc, 1UL, s, 4001ul);
aprsstr_Append(s, 4001ul, ":[", 3ul);
aprsstr_Append(s, 4001ul, fn, fn_len);
aprsstr_Append(s, 4001ul, "] ", 3ul);
aprsstr_Append(s, 4001ul, h, h_len);
osi_WrStrLn(s, 4001ul);
X2C_PFREE(h);
X2C_PFREE(fn);
} /* end err() */
static void initroutes(char fn[], uint32_t fn_len)
{
int32_t fd;
char call[201];
char b[201];
uint32_t lc;
uint32_t j;
uint32_t i;
char dbcin0;
char all;
char bci;
char bco;
char spoof;
uint32_t ip;
uint32_t dp;
X2C_PCOPY((void **)&fn,fn_len);
fd = osi_OpenRead(fn, fn_len);
if (osic_FdValid(fd)) {
lc = 1UL;
for (;;) {
i = 0UL;
do {
if (osi_RdBin(fd, (char *) &b[i], 1u/1u, 1UL)<1L) {
goto loop_exit;
}
++i;
} while (!(i>=200UL || b[i-1UL]=='\012'));
b[i] = 0;
if (b[0U]!='#') {
i = 0UL;
if (!Str2Call(b, 201ul, &i, 7UL, call, 201ul)) {
err("wrong SSID in Init File", 24ul, fn, fn_len, lc);
}
while (b[i]==' ') ++i;
spoof = b[i]=='p';
if (spoof) ++i;
all = b[i]=='A';
if (all) ++i;
bci = b[i]=='b';
if (bci) ++i;
bco = b[i]=='B';
if (bco) ++i;
while (b[i]==' ') ++i;
if (all && bco) {
err("Broadcast out AND get-all? in Init File", 40ul, fn,
fn_len, lc);
}
j = 0UL;
while ((uint8_t)b[i]>' ' && b[i]!='#') {
b[j] = b[i];
++j;
++i;
}
b[j] = 0;
if (GetIp1(b, 201ul, &ip, &dp)<0L) {
err("wrong IP:PORT in Init File", 27ul, fn, fn_len, lc);
}
else {
AddIp(ip, dp, 1, spoof, &dbcin0, bci, bco, all, call, 201ul);
}
}
++lc;
}
loop_exit:;
osic_Close(fd);
}
else Err("-i File not found", 18ul);
X2C_PFREE(fn);
} /* end initroutes() */
static char ubuf[338];
static int32_t blen;
static int32_t res;
static uint32_t fromip;
static uint32_t userdport;
static uint32_t lastlist;
static char dbcin;
static pUSER voidu;
X2C_STACK_LIMIT(100000l)
extern int main(int argc, char **argv)
{
X2C_BEGIN(&argc,argv,1,4000000l,8000000l);
if (sizeof(RAWCALL)!=7) X2C_ASSERT(0);
aprsstr_BEGIN();
osi_BEGIN();
Gencrctab();
noinf = 1;
show = 0;
peertopeer = 0;
defaultbcin = 0;
defaultbcout = 0;
touserport = 0UL;
digisock = -1L;
maxentries = 1000UL;
lifetime = 604800UL;
alllifetime = 600UL;
users = 0;
initfn[0U] = 0;
wrfn[0U] = 0;
broadcastdest[0U] = 0;
parms();
if (initfn[0U]) initroutes(initfn, 1025ul);
modified = 1;
if (!peertopeer && digisock<0L) Err("need -u parameter", 18ul);
usersock = openudp();
if ((touserport==0UL || usersock<0L) || bindudp(usersock, touserport)<0L) {
Err("cannot bind userport (-p userport)", 35ul);
}
systime = osic_time();
for (;;) {
fdclr();
if (digisock>=0L) fdsetr((uint32_t)digisock);
fdsetr((uint32_t)usersock);
if (selectrw(15UL, 0UL)>0L) {
if (digisock>=0L && issetr((uint32_t)digisock)) {
/* data from digi */
fromip = digiip;
blen = getudp(digisock, ubuf, 338ul, &fromip, &userdport,
checkdigiip);
if (blen>=17L) {
if (show) {
osi_WrStr("> from digi", 12ul);
ShowFrame(ubuf, 338ul, (uint32_t)(blen-2L), noinf);
}
if (!sendtouser(ubuf, 338ul, blen, 1, 1, digiip,
userdport) && show) {
osi_WrStrLn(" digi out user not found", 25ul);
}
if (show) osi_WrStrLn("-----", 6ul);
}
}
if (issetr((uint32_t)usersock)) {
/* data from user */
fromip = 0UL;
blen = getudp(usersock, ubuf, 338ul, &fromip, &userdport, 0);
if (blen>=17L) {
if (show) {
osi_WrStr("> from user ", 13ul);
showpip(fromip, userdport);
ShowFrame(ubuf, 338ul, (uint32_t)(blen-2L), noinf);
}
AddIp(fromip, userdport, 0, 0, &dbcin, defaultbcin,
defaultbcout, 0, ubuf, 338ul);
modified = 1;
if (digisock>=0L) {
res = udpsend(digisock, ubuf, blen, todigiport, digiip);
}
if (!sendtouser(ubuf, 338ul, blen, 0, dbcin, fromip,
userdport) && show) {
osi_WrStrLn(" peer-to-peer no user found", 28ul);
}
if (show) osi_WrStrLn("-----", 6ul);
}
}
}
systime = osic_time();
if (lastlist+15UL<systime || lastlist>systime) {
voidu = Realloc(0); /* cyclic purge */
if (modified && wrfn[0U]) {
listtab(wrfn, 1025ul);
modified = 0;
}
lastlist = systime;
}
}
X2C_EXIT();
return 0;
}
X2C_MAIN_DEFINITION