mirror of git://vps1.g8bpq.net/linbpq
parent
44916f4739
commit
c3e618e682
@ -0,0 +1,551 @@
|
||||
/*
|
||||
Copyright 2001-2022 John Wiseman G8BPQ
|
||||
|
||||
This file is part of LinBPQ/BPQ32.
|
||||
|
||||
LinBPQ/BPQ32 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.
|
||||
|
||||
LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
|
||||
*/
|
||||
|
||||
/*
|
||||
Netrom over TCP Support
|
||||
|
||||
This is intended for operation over radio links with an IP interface, eg New Packet Radio or possibly microwave links
|
||||
|
||||
To simplify interface to the rest of the oode dummy LINK and PORT records are created
|
||||
|
||||
Packet Format is Length (2 byte little endian) Call (10 bytes ASCII) NETROM L3/4 Packet, starting 0xcf (to detect framing errors).
|
||||
|
||||
A TCP message can contain multiple packets and/or partial packets
|
||||
|
||||
It uses the Telnet Server, with port defined in NETROMPORT
|
||||
|
||||
ROUTE definitions have an extra field, the TCP Port Number
|
||||
|
||||
*/
|
||||
|
||||
//#pragma data_seg("_BPQDATA")
|
||||
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "time.h"
|
||||
#include "stdio.h"
|
||||
#include <fcntl.h>
|
||||
//#include "vmm.h"
|
||||
|
||||
#include "cheaders.h"
|
||||
#include "asmstrucs.h"
|
||||
#include "telnetserver.h"
|
||||
|
||||
#define NETROM_PID 0xCF
|
||||
|
||||
void NETROMConnectionLost(struct ConnectionInfo * sockptr);
|
||||
int DataSocket_ReadNETROM(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info, int portNo);
|
||||
int NETROMTCPConnect(struct ROUTE * Route, struct ConnectionInfo * sockptr);
|
||||
void NETROMConnected(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info);
|
||||
VOID SendRTTMsg(struct ROUTE * Route);
|
||||
BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE);
|
||||
VOID NETROMMSG(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG);
|
||||
int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS);
|
||||
VOID L3LINKCLOSED(struct _LINKTABLE * LINK, int Reason);
|
||||
|
||||
struct NRTCPMsg
|
||||
{
|
||||
short Length;
|
||||
char Call[10];
|
||||
unsigned char PID;
|
||||
char Packet[1024];
|
||||
};
|
||||
|
||||
struct NRTCPSTRUCT
|
||||
{
|
||||
struct ConnectionInfo * sockptr;
|
||||
struct _LINKTABLE * LINK; // Dummy Link Record for this ROUTE
|
||||
struct ROUTE * Route; // May need backlink
|
||||
char Call[10];
|
||||
};
|
||||
|
||||
struct NRTCPSTRUCT * NRTCPInfo[256] = {0};
|
||||
|
||||
// Do we want to use normal TCP server connections, which are limited, or our own. Let's try our own for now
|
||||
|
||||
struct ConnectionInfo * AllocateNRTCPRec()
|
||||
{
|
||||
struct ConnectionInfo * sockptr = 0;
|
||||
struct NRTCPSTRUCT * Info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
if (NRTCPInfo[i] == 0)
|
||||
{
|
||||
// only allocate as many as needed
|
||||
|
||||
Info = NRTCPInfo[i] = (struct NRTCPSTRUCT *)zalloc(sizeof(struct NRTCPSTRUCT));
|
||||
Info->sockptr = (struct ConnectionInfo *)zalloc(sizeof(struct ConnectionInfo));
|
||||
Info->LINK = (struct _LINKTABLE *)zalloc(sizeof(struct _LINKTABLE));
|
||||
Info->sockptr->Number = i;
|
||||
}
|
||||
else
|
||||
Info = NRTCPInfo[i];
|
||||
|
||||
sockptr = Info->sockptr;
|
||||
|
||||
if (sockptr->SocketActive == FALSE)
|
||||
{
|
||||
sockptr->SocketActive = TRUE;
|
||||
sockptr->ConnectTime = sockptr->LastSendTime = time(NULL);
|
||||
|
||||
Debugprintf("NRTCP Allocated %d", i);
|
||||
return sockptr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void checkNRTCPSockets(int portNo)
|
||||
{
|
||||
SOCKET sock;
|
||||
int Active = 0;
|
||||
SOCKET maxsock;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set readfd, writefd, exceptfd;
|
||||
|
||||
struct ConnectionInfo * sockptr;
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0; // poll
|
||||
|
||||
maxsock = 0;
|
||||
|
||||
FD_ZERO(&readfd);
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&exceptfd);
|
||||
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
if (NRTCPInfo[i] == 0)
|
||||
break; // only as many as have been used
|
||||
|
||||
sockptr = NRTCPInfo[i]->sockptr;
|
||||
|
||||
if (sockptr->SocketActive == 0)
|
||||
continue;
|
||||
|
||||
if (sockptr->Connecting)
|
||||
{
|
||||
// look for complete or failed
|
||||
|
||||
FD_SET(sockptr->socket, &writefd);
|
||||
FD_SET(sockptr->socket, &exceptfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
FD_SET(sockptr->socket, &readfd);
|
||||
FD_SET(sockptr->socket, &exceptfd);
|
||||
}
|
||||
|
||||
Active++;
|
||||
|
||||
if (sockptr->socket > maxsock)
|
||||
maxsock = sockptr->socket;
|
||||
}
|
||||
|
||||
if (Active)
|
||||
{
|
||||
retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);
|
||||
|
||||
if (retval == -1)
|
||||
{
|
||||
perror("data select");
|
||||
Debugprintf("NRTCP Select Error %d Active %d", WSAGetLastError(), Active);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (retval)
|
||||
{
|
||||
// see who has data
|
||||
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
if (NRTCPInfo[i] == 0)
|
||||
break;
|
||||
|
||||
sockptr = NRTCPInfo[i]->sockptr;
|
||||
|
||||
if (sockptr->SocketActive == 0)
|
||||
continue;
|
||||
|
||||
sock = sockptr->socket;
|
||||
|
||||
if (FD_ISSET(sock, &writefd))
|
||||
NETROMConnected(sockptr, sock, NRTCPInfo[i]);
|
||||
|
||||
if (FD_ISSET(sock, &readfd))
|
||||
DataSocket_ReadNETROM(sockptr, sock, NRTCPInfo[i], portNo);
|
||||
|
||||
if (FD_ISSET(sock, &exceptfd))
|
||||
NETROMConnectionLost(sockptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int NETROMOpenConnection(struct ROUTE * Route)
|
||||
{
|
||||
struct NRTCPSTRUCT * Info;
|
||||
struct ConnectionInfo * sockptr;
|
||||
|
||||
Debugprintf("Opening NRTCP Connection");
|
||||
|
||||
if (Route->TCPSession)
|
||||
{
|
||||
// SESSION ALREADY EXISTS
|
||||
|
||||
sockptr = Route->TCPSession->sockptr;
|
||||
|
||||
if (sockptr->Connected || sockptr->Connecting)
|
||||
return TRUE;
|
||||
|
||||
// previous connect failed
|
||||
}
|
||||
else
|
||||
{
|
||||
sockptr = AllocateNRTCPRec();
|
||||
|
||||
if (sockptr == NULL)
|
||||
return 0;
|
||||
|
||||
Info = Route->TCPSession = NRTCPInfo[sockptr->Number];
|
||||
memcpy(Info->Call, MYNETROMCALL, 10);
|
||||
Route->NEIGHBOUR_LINK = Info->LINK;
|
||||
|
||||
Info->Route = Route;
|
||||
Info->LINK->NEIGHBOUR = Route;
|
||||
Info->LINK->LINKPORT = GetPortTableEntryFromPortNum(Route->NEIGHBOUR_PORT);
|
||||
}
|
||||
|
||||
return NETROMTCPConnect(Route, sockptr);
|
||||
|
||||
}
|
||||
|
||||
int NETROMTCPConnect(struct ROUTE * Route, struct ConnectionInfo * sockptr)
|
||||
{
|
||||
int err;
|
||||
u_long param=1;
|
||||
BOOL bcopt=TRUE;
|
||||
SOCKET sock;
|
||||
struct sockaddr_in sinx;
|
||||
int addrlen=sizeof(sinx);
|
||||
char PortString[20];
|
||||
struct addrinfo hints, *res = 0, *saveres;
|
||||
int Port = Route->TCPPort;
|
||||
|
||||
sprintf(PortString, "%d", Port);
|
||||
|
||||
// get host info, make socket, and connect it
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
|
||||
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
|
||||
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
getaddrinfo(Route->TCPHost, PortString, &hints, &res);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
err = WSAGetLastError();
|
||||
Debugprintf("Resolve HostName %s Failed - Error %d", Route->TCPHost, err);
|
||||
return FALSE; // Resolve failed
|
||||
}
|
||||
|
||||
// Step thorough the list of hosts
|
||||
|
||||
saveres = res; // Save for free
|
||||
|
||||
sock = sockptr->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
|
||||
|
||||
if (sock == INVALID_SOCKET)
|
||||
{
|
||||
Debugprintf, ("Netrom over TCP Create Socket Failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ioctl(sock, FIONBIO, ¶m);
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
|
||||
|
||||
|
||||
if (connect(sock, res->ai_addr, (int)res->ai_addrlen) == 0)
|
||||
{
|
||||
//
|
||||
// Connected successful
|
||||
//
|
||||
|
||||
sockptr->Connected = TRUE;
|
||||
freeaddrinfo(saveres);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
freeaddrinfo(saveres);
|
||||
|
||||
err=WSAGetLastError();
|
||||
|
||||
if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK
|
||||
{
|
||||
// Connect in Progress
|
||||
|
||||
sockptr->Connecting = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connect failed
|
||||
|
||||
closesocket(sockptr->socket);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void NETROMConnectionAccepted(struct ConnectionInfo * sockptr)
|
||||
{
|
||||
// Not sure we can do much here until first message arrives with callsign
|
||||
|
||||
sockptr->Connected = TRUE;
|
||||
Debugprintf("NRTCP Connection Accepted");
|
||||
}
|
||||
|
||||
void NETROMConnected(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info)
|
||||
{
|
||||
// Connection Complete
|
||||
|
||||
Debugprintf("NRTCP Connected");
|
||||
|
||||
sockptr->Connecting = FALSE;
|
||||
sockptr->Connected = TRUE;
|
||||
|
||||
Info->LINK->L2STATE = 5;
|
||||
|
||||
if (Info->Route->INP3Node)
|
||||
SendRTTMsg(Info->Route);
|
||||
}
|
||||
|
||||
int DataSocket_ReadNETROM(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info, int portNo)
|
||||
{
|
||||
int len=0, maxlen;
|
||||
struct NRTCPMsg * Msg;
|
||||
struct _L3MESSAGEBUFFER * L3Msg;
|
||||
struct ROUTE * Route;
|
||||
UCHAR axCall[7];
|
||||
PMESSAGE Buffer;
|
||||
|
||||
ioctl(sock,FIONREAD,&len);
|
||||
|
||||
maxlen = InputBufferLen - sockptr->InputLen;
|
||||
|
||||
if (len > maxlen) len = maxlen;
|
||||
|
||||
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
||||
|
||||
if (len == SOCKET_ERROR || len == 0)
|
||||
{
|
||||
// Failed or closed - clear connection
|
||||
|
||||
NETROMConnectionLost(sockptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sockptr->InputLen += len;
|
||||
|
||||
// Process data
|
||||
|
||||
checkLen:
|
||||
|
||||
// See if we have a whole packet
|
||||
|
||||
Msg = (struct NRTCPMsg *)&sockptr->InputBuffer[0];
|
||||
|
||||
if (Msg->Length > sockptr->InputLen) // if not got whole frame wait
|
||||
return 0;
|
||||
|
||||
if (Info->Call[0] == 0)
|
||||
{
|
||||
// first packet - do we need to do anything?
|
||||
|
||||
// This must be an incoming connection as Call is set before calling so need to find route record and set things up.
|
||||
|
||||
memcpy(Info->Call, Msg->Call, 10);
|
||||
|
||||
ConvToAX25(Msg->Call, axCall);
|
||||
|
||||
if (FindNeighbour(axCall, portNo, &Route))
|
||||
{
|
||||
Info->Route = Route;
|
||||
Route->NEIGHBOUR_LINK = Info->LINK;
|
||||
Info->LINK->NEIGHBOUR = Route;
|
||||
Info->LINK->LINKPORT = GetPortTableEntryFromPortNum(Route->NEIGHBOUR_PORT);
|
||||
Route->TCPSession = Info;
|
||||
Info->LINK->L2STATE = 5;
|
||||
|
||||
if (Info->Route->INP3Node)
|
||||
SendRTTMsg(Info->Route);
|
||||
}
|
||||
else
|
||||
goto seeifMore; // Should we kill connection?
|
||||
}
|
||||
|
||||
|
||||
if (memcmp(Info->Call, Msg->Call, 10) != 0)
|
||||
{
|
||||
// something wrong - maybe connection reused
|
||||
}
|
||||
|
||||
// Format as if come from an ax.25 link
|
||||
|
||||
L3Msg = GetBuff();
|
||||
|
||||
if (L3Msg == 0)
|
||||
goto seeifMore;
|
||||
|
||||
L3Msg->LENGTH = (Msg->Length - 12) + MSGHDDRLEN;
|
||||
L3Msg->Next = 0;
|
||||
L3Msg->Port = 0;
|
||||
L3Msg->L3PID = NETROM_PID;
|
||||
memcpy(&L3Msg->L3SRCE, Msg->Packet, Msg->Length - 13);
|
||||
|
||||
// Create a dummy L2 message so we can trace it
|
||||
|
||||
Buffer = GetBuff();
|
||||
|
||||
if (Buffer)
|
||||
{
|
||||
Buffer->CHAIN = 0;
|
||||
Buffer->CTL = 0;
|
||||
Buffer->PORT = portNo;
|
||||
|
||||
ConvToAX25(Info->Call, Buffer->ORIGIN);
|
||||
ConvToAX25(MYNETROMCALL, Buffer->DEST);
|
||||
|
||||
memcpy(Buffer->L2DATA, &L3Msg->L3SRCE[0], Msg->Length - 13);
|
||||
Buffer->ORIGIN[6] |= 1; // Set end of calls
|
||||
Buffer->PID = NETROM_PID;
|
||||
Buffer->LENGTH = Msg->Length + 10;
|
||||
time(&Buffer->Timestamp);
|
||||
|
||||
BPQTRACE(Buffer, FALSE);
|
||||
ReleaseBuffer(Buffer);
|
||||
}
|
||||
|
||||
NETROMMSG(Info->LINK, L3Msg);
|
||||
|
||||
seeifMore:
|
||||
|
||||
sockptr->InputLen -= Msg->Length;
|
||||
|
||||
if (sockptr->InputLen > 0)
|
||||
{
|
||||
memmove(sockptr->InputBuffer, &sockptr->InputBuffer[Msg->Length], sockptr->InputLen);
|
||||
goto checkLen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOID TCPNETROMSend(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame)
|
||||
{
|
||||
struct NRTCPMsg Msg;
|
||||
unsigned char * Data = (unsigned char *)&Frame->L3SRCE[0];
|
||||
int DataLen = Frame->LENGTH - (MSGHDDRLEN + 1); // Not including PID
|
||||
int Ret;
|
||||
PMESSAGE Buffer;
|
||||
|
||||
Msg.Length = DataLen + 13; // include PID
|
||||
memcpy(Msg.Call, MYNETROMCALL, 10);
|
||||
Msg.PID = NETROM_PID;
|
||||
memcpy(Msg.Packet, Data, DataLen);
|
||||
|
||||
if (Route->TCPSession == 0)
|
||||
return;
|
||||
|
||||
Ret = send(Route->TCPSession->sockptr->socket, (char *)&Msg, DataLen + 13, 0);
|
||||
|
||||
// Create a dummy L2 message so we can trace it
|
||||
|
||||
Buffer = GetBuff();
|
||||
|
||||
if (Buffer)
|
||||
{
|
||||
Buffer->CHAIN = 0;
|
||||
Buffer->CTL = 0;
|
||||
Buffer->PORT = Route->NEIGHBOUR_PORT | 128; // TX Flag
|
||||
|
||||
ConvToAX25(Route->TCPSession->Call, Buffer->DEST);
|
||||
ConvToAX25(MYNETROMCALL, Buffer->ORIGIN);
|
||||
|
||||
memcpy(Buffer->L2DATA, &Frame->L3SRCE[0], DataLen);
|
||||
Buffer->ORIGIN[6] |= 1; // Set end of calls
|
||||
Buffer->PID = NETROM_PID;
|
||||
Buffer->LENGTH = DataLen + 15 + MSGHDDRLEN;
|
||||
time(&Buffer->Timestamp);
|
||||
|
||||
BPQTRACE(Buffer, FALSE);
|
||||
ReleaseBuffer(Buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NETROMConnectionLost(struct ConnectionInfo * sockptr)
|
||||
{
|
||||
struct NRTCPSTRUCT * Info = NRTCPInfo[sockptr->Number];
|
||||
struct ROUTE * Route;
|
||||
|
||||
closesocket(sockptr->socket);
|
||||
|
||||
// If there is an attached route (there should be) clear all connections
|
||||
|
||||
if (Info)
|
||||
{
|
||||
Route = Info->Route;
|
||||
|
||||
if (sockptr->Connected)
|
||||
L3LINKCLOSED(Info->LINK, LINKLOST);
|
||||
|
||||
if (sockptr->Connecting)
|
||||
L3LINKCLOSED(Info->LINK, SETUPFAILED);
|
||||
|
||||
Route->TCPSession = 0;
|
||||
|
||||
Info->Call[0] = 0;
|
||||
}
|
||||
|
||||
sockptr->SocketActive = FALSE;
|
||||
|
||||
memset(sockptr, 0, sizeof(struct ConnectionInfo));
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
Reference in new issue