2022-08-28 09:35:46 +01:00
/*
2022-11-14 14:02:28 +00:00
Copyright 2001 - 2022 John Wiseman G8BPQ
2022-08-28 09:35:46 +01:00
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
*/
//
// DLL to provide interface to allow G8BPQ switch to use MultoPSK ALE400 Mode
//
// Uses BPQ EXTERNAL interface
//
# define _CRT_SECURE_NO_DEPRECATE
# define _CRT_SECURE_NO_DEPRECATE
# include "CHeaders.h"
# include <stdio.h>
# include <time.h>
# include "tncinfo.h"
# include "bpq32.h"
# define VERSION_MAJOR 2
# define VERSION_MINOR 0
# define SD_RECEIVE 0x00
# define SD_SEND 0x01
# define SD_BOTH 0x02
# define TIMESTAMP 352
# define CONTIMEOUT 1200
# define AGWHDDRLEN sizeof(struct AGWHEADER)
extern int ( WINAPI FAR * GetModuleFileNameExPtr ) ( ) ;
//int ResetExtDriver(int num);
static void ConnecttoMPSKThread ( void * portptr ) ;
void CreateMHWindow ( ) ;
int Update_MH_List ( struct in_addr ipad , char * call , char proto ) ;
2024-12-16 17:54:16 +00:00
static int ConnecttoMPSK ( int port ) ;
2022-08-28 09:35:46 +01:00
static int ProcessReceivedData ( int bpqport ) ;
static int ProcessLine ( char * buf , int Port ) ;
int KillTNC ( struct TNCINFO * TNC ) ;
int RestartTNC ( struct TNCINFO * TNC ) ;
VOID ProcessMPSKPacket ( struct TNCINFO * TNC , char * Message , int Len ) ;
struct TNCINFO * GetSessionKey ( char * key , struct TNCINFO * TNC ) ;
static VOID SendData ( struct TNCINFO * TNC , char * Msg , int MsgLen ) ;
static VOID DoMonitorHddr ( struct TNCINFO * TNC , struct AGWHEADER * RXHeader , UCHAR * Msg ) ;
VOID SendRPBeacon ( struct TNCINFO * TNC ) ;
extern UCHAR BPQDirectory [ ] ;
# define MAXMPSKPORTS 16
//LOGFONT LFTTYFONT ;
//HFONT hFont ;
static int MPSKChannel [ MAXBPQPORTS + 1 ] ; // BPQ Port to MPSK Port
static int BPQPort [ MAXMPSKPORTS ] [ MAXBPQPORTS + 1 ] ; // MPSK Port and Connection to BPQ Port
2023-06-29 18:13:31 +01:00
extern int MasterPort [ MAXBPQPORTS + 1 ] ; // Pointer to first BPQ port for a specific MPSK host
2022-08-28 09:35:46 +01:00
// Each port may be on a different machine. We only open one connection to each MPSK instance
static char * MPSKSignon [ MAXBPQPORTS + 1 ] ; // Pointer to message for secure signin
static unsigned int MPSKInst = 0 ;
static int AttachedProcesses = 0 ;
static HWND hResWnd , hMHWnd ;
static BOOL GotMsg ;
static HANDLE STDOUT = 0 ;
//SOCKET sock;
static SOCKADDR_IN sinx ;
static SOCKADDR_IN rxaddr ;
static SOCKADDR_IN destaddr [ MAXBPQPORTS + 1 ] ;
static int addrlen = sizeof ( sinx ) ;
//static short MPSKPort=0;
static time_t ltime , lasttime [ MAXBPQPORTS + 1 ] ;
static BOOL CONNECTING [ MAXBPQPORTS + 1 ] ;
static BOOL CONNECTED [ MAXBPQPORTS + 1 ] ;
//HANDLE hInstance;
static fd_set readfs ;
static fd_set writefs ;
static fd_set errorfs ;
static struct timeval timeout ;
# ifndef LINBPQ
static BOOL CALLBACK EnumTNCWindowsProc ( HWND hwnd , LPARAM lParam )
{
char wtext [ 200 ] ;
struct TNCINFO * TNC = ( struct TNCINFO * ) lParam ;
UINT ProcessId ;
char FN [ MAX_PATH ] = " " ;
if ( TNC - > ProgramPath = = NULL )
return FALSE ;
GetWindowText ( hwnd , wtext , 199 ) ;
if ( strstr ( wtext , " * MULTIPSK " ) )
{
GetWindowThreadProcessId ( hwnd , & ProcessId ) ;
TNC - > PID = ProcessId ;
return FALSE ;
}
return ( TRUE ) ;
}
# endif
static size_t ExtProc ( int fn , int port , PDATAMESSAGE buff )
{
PMSGWITHLEN buffptr ;
unsigned int txlen = 0 ;
struct TNCINFO * TNC = TNCInfo [ port ] ;
int Stream = 0 ;
struct STREAMINFO * STREAM ;
int TNCOK ;
if ( TNC = = NULL )
return 0 ; // Port not defined
// Look for attach on any call
for ( Stream = 0 ; Stream < = TNC - > MPSKInfo - > MaxSessions ; Stream + + )
{
STREAM = & TNC - > Streams [ Stream ] ;
if ( TNC - > PortRecord - > ATTACHEDSESSIONS [ Stream ] & & TNC - > Streams [ Stream ] . Attached = = 0 )
{
char Cmd [ 80 ] ;
int len ;
// New Attach
int calllen ;
STREAM - > Attached = TRUE ;
calllen = ConvFromAX25 ( TNC - > PortRecord - > ATTACHEDSESSIONS [ Stream ] - > L4USER , STREAM - > MyCall ) ;
STREAM - > MyCall [ calllen ] = 0 ;
STREAM - > FramesOutstanding = 0 ;
// Stop Scanning
sprintf ( Cmd , " %d SCANSTOP " , TNC - > Port ) ;
2023-05-16 16:40:12 +01:00
Rig_Command ( ( TRANSPORTENTRY * ) - 1 , Cmd ) ;
2022-08-28 09:35:46 +01:00
len = sprintf ( Cmd , " %cSTOP_BEACON_ARQ_FAE \x1b " , ' \x1a ' ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Cmd ) ; // Savde till not transmitting
else
send ( TNC - > TCPSock , Cmd , len , 0 ) ;
}
}
switch ( fn )
{
case 1 : // poll
if ( MasterPort [ port ] = = port )
{
// Only on first port using a host
if ( TNC - > CONNECTED = = FALSE & & TNC - > CONNECTING = = FALSE )
{
// See if time to reconnect
time ( & ltime ) ;
if ( ltime - lasttime [ port ] > 9 )
{
ConnecttoMPSK ( port ) ;
lasttime [ port ] = ltime ;
}
}
FD_ZERO ( & readfs ) ;
if ( TNC - > CONNECTED ) FD_SET ( TNC - > TCPSock , & readfs ) ;
FD_ZERO ( & writefs ) ;
if ( TNC - > CONNECTING ) FD_SET ( TNC - > TCPSock , & writefs ) ; // Need notification of Connect
if ( TNC - > BPQtoWINMOR_Q ) FD_SET ( TNC - > TCPSock , & writefs ) ; // Need notification of busy clearing
FD_ZERO ( & errorfs ) ;
if ( TNC - > CONNECTING | | TNC - > CONNECTED ) FD_SET ( TNC - > TCPSock , & errorfs ) ;
if ( select ( ( int ) TNC - > TCPSock + 1 , & readfs , & writefs , & errorfs , & timeout ) > 0 )
{
// See what happened
if ( FD_ISSET ( TNC - > TCPSock , & readfs ) )
{
// data available
ProcessReceivedData ( port ) ;
}
if ( FD_ISSET ( TNC - > TCPSock , & writefs ) )
{
// Connect success
TNC - > CONNECTED = TRUE ;
TNC - > CONNECTING = FALSE ;
// If required, send signon
send ( TNC - > TCPSock , " \x1a " , 1 , 0 ) ;
send ( TNC - > TCPSock , " DIGITAL MODE ? " , 14 , 0 ) ;
send ( TNC - > TCPSock , " \x1b " , 1 , 0 ) ;
// EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC);
}
if ( FD_ISSET ( TNC - > TCPSock , & errorfs ) )
{
// if connecting, then failed, if connected then has just disconnected
// if (CONNECTED[port])
// if (!CONNECTING[port])
// {
// i=sprintf(ErrMsg, "MPSK Connection lost for BPQ Port %d\r\n", port);
// WritetoConsole(ErrMsg);
// }
CONNECTING [ port ] = FALSE ;
CONNECTED [ port ] = FALSE ;
}
}
}
// See if any frames for this port
for ( Stream = 0 ; Stream < = TNC - > MPSKInfo - > MaxSessions ; Stream + + )
{
STREAM = & TNC - > Streams [ Stream ] ;
// Have to time out connects, as TNC doesn't report failure
if ( STREAM - > Connecting )
{
STREAM - > Connecting - - ;
if ( STREAM - > Connecting = = 0 )
{
// Report Connect Failed, and drop back to command mode
buffptr = GetBuff ( ) ;
if ( buffptr )
{
buffptr - > Len = sprintf ( buffptr - > Data , " MPSK} Failure with %s \r " , STREAM - > RemoteCall ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
}
STREAM - > Connected = FALSE ; // Back to Command Mode
STREAM - > DiscWhenAllSent = 10 ;
// Send Disc to TNC
TidyClose ( TNC , Stream ) ;
}
}
if ( STREAM - > Attached )
CheckForDetach ( TNC , Stream , STREAM , TidyClose , ForcedClose , CloseComplete ) ;
if ( STREAM - > ReportDISC )
{
STREAM - > ReportDISC = FALSE ;
buff - > PORT = Stream ;
return - 1 ;
}
// if Busy, send buffer status poll
if ( STREAM - > PACTORtoBPQ_Q = = 0 )
{
if ( STREAM - > DiscWhenAllSent )
{
STREAM - > DiscWhenAllSent - - ;
if ( STREAM - > DiscWhenAllSent = = 0 )
STREAM - > ReportDISC = TRUE ; // Dont want to leave session attached. Causes too much confusion
}
}
else
{
int datalen ;
buffptr = Q_REM ( & STREAM - > PACTORtoBPQ_Q ) ;
datalen = ( int ) buffptr - > Len ;
buff - > PORT = Stream ; // Compatibility with Kam Driver
buff - > PID = 0xf0 ;
memcpy ( & buff - > L2DATA , & buffptr - > Data [ 0 ] , datalen ) ;
datalen + = sizeof ( void * ) + 4 ;
PutLengthinBuffer ( buff , datalen ) ;
ReleaseBuffer ( buffptr ) ;
return ( 1 ) ;
}
}
if ( TNC - > PortRecord - > UI_Q )
{
struct _MESSAGE * buffptr ;
SOCKET Sock ;
buffptr = Q_REM ( & TNC - > PortRecord - > UI_Q ) ;
Sock = TNCInfo [ MasterPort [ port ] ] - > TCPSock ;
ReleaseBuffer ( ( UINT * ) buffptr ) ;
}
return ( 0 ) ;
case 2 : // send
if ( ! TNCInfo [ MasterPort [ port ] ] - > CONNECTED ) return 0 ; // Don't try if not connected to TNC
Stream = buff - > PORT ;
STREAM = & TNC - > Streams [ Stream ] ;
// txlen=(buff[6]<<8) + buff[5] - 8;
txlen = GetLengthfromBuffer ( ( PDATAMESSAGE ) buff ) - 8 ;
if ( STREAM - > Connected )
{
SendData ( TNC , buff - > L2DATA , txlen ) ;
}
else
{
char Command [ 80 ] ;
int len ;
buff - > L2DATA [ txlen ] = 0 ;
_strupr ( buff - > L2DATA ) ;
if ( _memicmp ( buff - > L2DATA , " D \r " , 2 ) = = 0 )
{
TidyClose ( TNC , buff - > PORT ) ;
STREAM - > ReportDISC = TRUE ; // Tell Node
return 0 ;
}
// See if Local command (eg RADIO)
if ( _memicmp ( buff - > L2DATA , " RADIO " , 6 ) = = 0 )
{
sprintf ( buff - > L2DATA , " %d %s " , TNC - > Port , & buff - > L2DATA [ 6 ] ) ;
2023-05-16 16:40:12 +01:00
if ( Rig_Command ( TNC - > PortRecord - > ATTACHEDSESSIONS [ 0 ] - > L4CROSSLINK , buff - > L2DATA ) )
2022-08-28 09:35:46 +01:00
{
}
else
{
PMSGWITHLEN buffptr = GetBuff ( ) ;
if ( buffptr = = 0 ) return 1 ; // No buffers, so ignore
buffptr - > Len = sprintf ( buffptr - > Data , " %s " , buff - > L2DATA ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
}
return 1 ;
}
if ( STREAM - > Connecting & & _memicmp ( buff - > L2DATA , " ABORT " , 5 ) = = 0 )
{
len = sprintf ( Command , " %cSTOP_SELECTIVE_CALL_ARQ_FAE \x1b " , ' \x1a ' ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Command ) ; // Save till not transmitting
else
send ( TNC - > TCPSock , Command , len , 0 ) ;
TNC - > InternalCmd = TRUE ;
return ( 0 ) ;
}
if ( _memicmp ( buff - > L2DATA , " MODE " , 4 ) = = 0 )
{
buff - > L2DATA [ txlen - 1 ] = 0 ; // Remove CR
len = sprintf ( Command , " %cDIGITAL MODE %s \x1b " , ' \x1a ' , & buff - > L2DATA [ 5 ] ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Command ) ; // Save till not transmitting
else
send ( TNC - > TCPSock , Command , len , 0 ) ;
TNC - > InternalCmd = TRUE ;
return ( 0 ) ;
}
if ( _memicmp ( buff - > L2DATA , " INUSE? " , 6 ) = = 0 )
{
// Return Error if in use, OK if not
PMSGWITHLEN buffptr = GetBuff ( ) ;
int s = 0 ;
while ( s < = TNC - > MPSKInfo - > MaxSessions )
{
if ( s ! = Stream )
{
if ( TNC - > PortRecord - > ATTACHEDSESSIONS [ s ] )
{
buffptr - > Len = sprintf ( buffptr - > Data , " MPSK} Error - In use \r " ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
return 1 ; // Busy
}
}
s + + ;
}
buffptr - > Len = sprintf ( buffptr - > Data , " MPSK} Ok - Not in use \r " ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
return 1 ;
}
// See if a Connect Command.
if ( toupper ( buff - > L2DATA [ 0 ] ) = = ' C ' & & buff - > L2DATA [ 1 ] = = ' ' & & txlen > 2 ) // Connect
{
char * ptr ;
char * context ;
buff - > L2DATA [ txlen ] = 0 ;
_strupr ( buff - > L2DATA ) ;
memset ( STREAM - > RemoteCall , 0 , 10 ) ;
ptr = strtok_s ( & buff - > L2DATA [ 2 ] , " , \r " , & context ) ;
2022-10-03 15:55:07 +01:00
if ( ptr = = 0 )
{
PMSGWITHLEN buffptr = ( PMSGWITHLEN ) GetBuff ( ) ;
if ( buffptr )
{
buffptr - > Len = sprintf ( ( UCHAR * ) & buffptr - > Data [ 0 ] ,
" MPSK} Error - Call missing from C command \r " , STREAM - > MyCall , STREAM - > RemoteCall ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
}
STREAM - > DiscWhenAllSent = 10 ;
return 0 ;
}
2022-08-28 09:35:46 +01:00
strcpy ( STREAM - > RemoteCall , ptr ) ;
len = sprintf ( Command , " %cCALLSIGN_TO_CALL_ARQ_FAE %s%c%cSELECTIVE_CALL_ARQ_FAE \x1b " ,
' \x1a ' , STREAM - > RemoteCall , ' \x1b ' , ' \x1a ' ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Command ) ; // Save till not transmitting
else
send ( TNC - > TCPSock , Command , len , 0 ) ;
STREAM - > Connecting = TNC - > MPSKInfo - > ConnTimeOut ; // It doesn't report failure
// sprintf(Status, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
// SetDlgItemText(TNC->hDlg, IDC_TNCSTATE, Status);
return 0 ;
}
// Send any other command to Multipsk
buff - > L2DATA [ txlen - 1 ] = 0 ;
_strupr ( buff - > L2DATA ) ;
len = sprintf ( Command , " %c%s \x1b " , ' \x1a ' , buff - > L2DATA ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Command ) ; // Save till not transmitting
else
send ( TNC - > TCPSock , Command , len , 0 ) ;
TNC - > InternalCmd = TRUE ;
}
return ( 0 ) ;
case 3 :
Stream = ( int ) ( size_t ) buff ;
TNCOK = TNCInfo [ MasterPort [ port ] ] - > CONNECTED ;
STREAM = & TNC - > Streams [ Stream ] ;
if ( STREAM - > FramesOutstanding > 8 )
return ( 1 | TNCOK < < 8 | STREAM - > Disconnecting < < 15 ) ;
return TNCOK < < 8 | STREAM - > Disconnecting < < 15 ; // OK, but lock attach if disconnecting
break ;
case 4 : // reinit
shutdown ( TNC - > TCPSock , SD_BOTH ) ;
Sleep ( 100 ) ;
closesocket ( TNC - > TCPSock ) ;
TNC - > CONNECTED = FALSE ;
if ( TNC - > PID & & TNC - > WeStartedTNC )
{
KillTNC ( TNC ) ;
RestartTNC ( TNC ) ;
}
return ( 0 ) ;
case 5 : // Close
shutdown ( TNC - > TCPSock , SD_BOTH ) ;
Sleep ( 100 ) ;
closesocket ( TNC - > TCPSock ) ;
if ( TNC - > PID & & TNC - > WeStartedTNC )
{
KillTNC ( TNC ) ;
}
return 0 ;
}
return 0 ;
}
# ifndef LINBPQ
static KillTNC ( struct TNCINFO * TNC )
{
HANDLE hProc ;
if ( TNC - > PTTMode )
Rig_PTT ( TNC , FALSE ) ; // Make sure PTT is down
if ( TNC - > PID = = 0 ) return 0 ;
hProc = OpenProcess ( PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , FALSE , TNC - > PID ) ;
if ( hProc )
{
TerminateProcess ( hProc , 0 ) ;
CloseHandle ( hProc ) ;
}
TNC - > PID = 0 ; // So we don't try again
return 0 ;
}
static RestartTNC ( struct TNCINFO * TNC )
{
STARTUPINFO SInfo ; // pointer to STARTUPINFO
PROCESS_INFORMATION PInfo ; // pointer to PROCESS_INFORMATION
char HomeDir [ MAX_PATH ] ;
int i , ret ;
SInfo . cb = sizeof ( SInfo ) ;
SInfo . lpReserved = NULL ;
SInfo . lpDesktop = NULL ;
SInfo . lpTitle = NULL ;
SInfo . dwFlags = 0 ;
SInfo . cbReserved2 = 0 ;
SInfo . lpReserved2 = NULL ;
if ( TNC - > ProgramPath & & TNC - > DontRestart = = 0 )
{
strcpy ( HomeDir , TNC - > ProgramPath ) ;
i = strlen ( HomeDir ) ;
while ( - - i )
{
if ( HomeDir [ i ] = = ' / ' | | HomeDir [ i ] = = ' \\ ' )
{
HomeDir [ i ] = 0 ;
break ;
}
}
ret = CreateProcess ( TNC - > ProgramPath , " MultiPSK TCP_IP_ON " , NULL , NULL , FALSE , 0 , NULL , HomeDir , & SInfo , & PInfo ) ;
if ( ret )
TNC - > PID = PInfo . dwProcessId ;
return ret ;
}
return 0 ;
}
# endif
void * MPSKExtInit ( EXTPORTDATA * PortEntry )
{
int i , port ;
char Msg [ 255 ] ;
struct TNCINFO * TNC ;
char * ptr ;
//
// Will be called once for each MPSK port to be mapped to a BPQ Port
// The MPSK port number is in CHANNEL - A=0, B=1 etc
//
// The Socket to connect to is in IOBASE
//
port = PortEntry - > PORTCONTROL . PORTNUMBER ;
ReadConfigFile ( port , ProcessLine ) ;
TNC = TNCInfo [ port ] ;
if ( TNC = = NULL )
{
// Not defined in Config file
sprintf ( Msg , " ** Error - no info in BPQ32.cfg for this port \n " ) ;
WritetoConsole ( Msg ) ;
return ExtProc ;
}
TNC - > Port = port ;
TNC - > PortRecord = PortEntry ;
if ( PortEntry - > PORTCONTROL . PORTCALL [ 0 ] = = 0 )
memcpy ( TNC - > NodeCall , MYNODECALL , 10 ) ;
else
ConvFromAX25 ( & PortEntry - > PORTCONTROL . PORTCALL [ 0 ] , TNC - > NodeCall ) ;
if ( PortEntry - > PORTCONTROL . PORTINTERLOCK & & TNC - > RXRadio = = 0 & & TNC - > TXRadio = = 0 )
TNC - > RXRadio = TNC - > TXRadio = PortEntry - > PORTCONTROL . PORTINTERLOCK ;
PortEntry - > PORTCONTROL . PROTOCOL = 10 ;
PortEntry - > PERMITGATEWAY = TRUE ; // Can change ax.25 call on each stream
PortEntry - > PORTCONTROL . PORTQUALITY = 0 ;
PortEntry - > SCANCAPABILITIES = NONE ; // Scan Control - None
if ( PortEntry - > PORTCONTROL . PORTPACLEN = = 0 )
PortEntry - > PORTCONTROL . PORTPACLEN = 64 ;
ptr = strchr ( TNC - > NodeCall , ' ' ) ;
if ( ptr ) * ( ptr ) = 0 ; // Null Terminate
TNC - > Hardware = H_MPSK ;
MPSKChannel [ port ] = PortEntry - > PORTCONTROL . CHANNELNUM - 65 ;
PortEntry - > MAXHOSTMODESESSIONS = 1 ;
i = sprintf ( Msg , " MPSK Host %s Port %d \n " ,
TNC - > HostName , TNC - > TCPPort ) ;
WritetoConsole ( Msg ) ;
// See if we already have a port for this host
MasterPort [ port ] = port ;
for ( i = 1 ; i < port ; i + + )
{
if ( i = = port ) continue ;
if ( TNCInfo [ i ] & & TNCInfo [ i ] - > TCPPort = = TNC - > TCPPort & &
_stricmp ( TNCInfo [ i ] - > HostName , TNC - > HostName ) = = 0 )
{
MasterPort [ port ] = i ;
break ;
}
}
BPQPort [ PortEntry - > PORTCONTROL . CHANNELNUM - 65 ] [ MasterPort [ port ] ] = port ;
# ifndef LINBPQ
if ( MasterPort [ port ] = = port )
{
if ( EnumWindows ( EnumTNCWindowsProc , ( LPARAM ) TNC ) )
if ( TNC - > ProgramPath )
TNC - > WeStartedTNC = RestartTNC ( TNC ) ;
ConnecttoMPSK ( port ) ;
}
# endif
time ( & lasttime [ port ] ) ; // Get initial time value
// SendMessage(0x40eaa, WM_COMMAND, 0x03000eaa, 0x40eaa);
return ExtProc ;
}
static int ProcessLine ( char * buf , int Port )
{
UCHAR * ptr , * p_cmd ;
char * p_ipad = 0 ;
char * p_port = 0 ;
unsigned short WINMORport = 0 ;
int BPQport ;
int len = 510 ;
struct TNCINFO * TNC ;
struct MPSKINFO * AGW ;
char errbuf [ 256 ] ;
strcpy ( errbuf , buf ) ;
ptr = strtok ( buf , " \t \n \r " ) ;
if ( ptr = = NULL ) return ( TRUE ) ;
if ( * ptr = = ' # ' ) return ( TRUE ) ; // comment
if ( * ptr = = ' ; ' ) return ( TRUE ) ; // comment
if ( _stricmp ( buf , " ADDR " ) )
return FALSE ; // Must start with ADDR
ptr = strtok ( NULL , " \t \n \r " ) ;
BPQport = Port ;
p_ipad = ptr ;
TNC = TNCInfo [ BPQport ] = zalloc ( sizeof ( struct TNCINFO ) ) ;
AGW = TNC - > MPSKInfo = zalloc ( sizeof ( struct MPSKINFO ) ) ; // AGW Sream Mode Specific Data
AGW - > MaxSessions = 10 ;
AGW - > ConnTimeOut = CONTIMEOUT ;
TNC - > InitScript = malloc ( 1000 ) ;
TNC - > InitScript [ 0 ] = 0 ;
if ( p_ipad = = NULL )
p_ipad = strtok ( NULL , " \t \n \r " ) ;
if ( p_ipad = = NULL ) return ( FALSE ) ;
p_port = strtok ( NULL , " \t \n \r " ) ;
if ( p_port = = NULL ) return ( FALSE ) ;
TNC - > TCPPort = atoi ( p_port ) ;
TNC - > destaddr . sin_family = AF_INET ;
TNC - > destaddr . sin_port = htons ( TNC - > TCPPort ) ;
TNC - > HostName = malloc ( strlen ( p_ipad ) + 1 ) ;
if ( TNC - > HostName = = NULL ) return TRUE ;
strcpy ( TNC - > HostName , p_ipad ) ;
ptr = strtok ( NULL , " \t \n \r " ) ;
if ( ptr )
{
if ( _memicmp ( ptr , " PATH " , 4 ) = = 0 )
{
p_cmd = strtok ( NULL , " \n \r " ) ;
if ( p_cmd ) TNC - > ProgramPath = _strdup ( p_cmd ) ;
}
}
// Read Initialisation lines
while ( TRUE )
{
if ( GetLine ( buf ) = = 0 )
return TRUE ;
strcpy ( errbuf , buf ) ;
if ( memcmp ( buf , " **** " , 4 ) = = 0 )
return TRUE ;
ptr = strchr ( buf , ' ; ' ) ;
if ( ptr )
{
* ptr + + = 13 ;
* ptr = 0 ;
}
if ( _memicmp ( buf , " CONTIMEOUT " , 10 ) = = 0 )
AGW - > ConnTimeOut = atoi ( & buf [ 11 ] ) * 10 ;
else
if ( _memicmp ( buf , " UPDATEMAP " , 9 ) = = 0 )
TNC - > PktUpdateMap = TRUE ;
else
if ( _memicmp ( buf , " ALEBEACON " , 9 ) = = 0 ) // Send Beacon after each session
TNC - > MPSKInfo - > Beacon = TRUE ;
else
if ( _memicmp ( buf , " DEFAULTMODE " , 11 ) = = 0 ) // Send Beacon after each session
strcpy ( TNC - > MPSKInfo - > DefaultMode , & buf [ 12 ] ) ;
else
strcat ( TNC - > InitScript , buf ) ;
}
return ( TRUE ) ;
}
static int ConnecttoMPSK ( int port )
{
_beginthread ( ConnecttoMPSKThread , 0 , ( void * ) ( size_t ) port ) ;
return 0 ;
}
VOID ConnecttoMPSKThread ( void * portptr )
{
int port = ( int ) ( size_t ) portptr ;
char Msg [ 255 ] ;
int err , i ;
u_long param = 1 ;
BOOL bcopt = TRUE ;
struct hostent * HostEnt ;
struct TNCINFO * TNC = TNCInfo [ port ] ;
Sleep ( 5000 ) ; // Allow init to complete
TNC - > destaddr . sin_addr . s_addr = inet_addr ( TNC - > HostName ) ;
if ( TNC - > destaddr . sin_addr . s_addr = = INADDR_NONE )
{
// Resolve name to address
HostEnt = gethostbyname ( TNC - > HostName ) ;
if ( ! HostEnt ) return ; // Resolve failed
memcpy ( & TNC - > destaddr . sin_addr . s_addr , HostEnt - > h_addr , 4 ) ;
memcpy ( & TNC - > Datadestaddr . sin_addr . s_addr , HostEnt - > h_addr , 4 ) ;
}
if ( TNC - > TCPSock )
closesocket ( TNC - > TCPSock ) ;
TNC - > TCPSock = 0 ;
TNC - > TCPSock = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( TNC - > TCPSock = = INVALID_SOCKET )
{
i = sprintf ( Msg , " Socket Failed for MPSK socket - error code = %d \n " , WSAGetLastError ( ) ) ;
WritetoConsole ( Msg ) ;
return ;
}
sinx . sin_family = AF_INET ;
sinx . sin_addr . s_addr = INADDR_ANY ;
sinx . sin_port = 0 ;
TNC - > CONNECTING = TRUE ;
if ( connect ( TNC - > TCPSock , ( LPSOCKADDR ) & TNC - > destaddr , sizeof ( TNC - > destaddr ) ) = = 0 )
{
//
// Connected successful
//
TNC - > CONNECTED = TRUE ;
}
else
{
if ( TNC - > Alerted = = FALSE )
{
err = WSAGetLastError ( ) ;
i = sprintf ( Msg , " Connect Failed for MPSK socket - error code = %d \n " , err ) ;
WritetoConsole ( Msg ) ;
MySetWindowText ( TNC - > xIDC_COMMSSTATE , " Connection to TNC failed " ) ;
TNC - > Alerted = TRUE ;
}
TNC - > CONNECTING = FALSE ;
return ;
}
TNC - > LastFreq = 0 ; // so V4 display will be updated
MySetWindowText ( TNC - > xIDC_COMMSSTATE , " Connected to MPSK TNC " ) ;
return ;
}
static int ProcessReceivedData ( int port )
{
unsigned int bytes ;
int i ;
char ErrMsg [ 255 ] ;
char Message [ 500 ] ;
struct TNCINFO * TNC = TNCInfo [ port ] ;
// Need to extract messages from byte stream
bytes = recv ( TNC - > TCPSock , ( char * ) & Message , 500 , 0 ) ;
if ( bytes = = SOCKET_ERROR )
{
// i=sprintf(ErrMsg, "Read Failed for MPSK socket - error code = %d\r\n", WSAGetLastError());
// WritetoConsole(ErrMsg);
closesocket ( TNC - > TCPSock ) ;
TNC - > CONNECTED = FALSE ;
if ( TNC - > Streams [ 0 ] . Attached )
TNC - > Streams [ 0 ] . ReportDISC = TRUE ;
return ( 0 ) ;
}
if ( bytes = = 0 )
{
// zero bytes means connection closed
i = sprintf ( ErrMsg , " MPSK Connection closed for BPQ Port %d \n " , port ) ;
WritetoConsole ( ErrMsg ) ;
TNC - > CONNECTED = FALSE ;
if ( TNC - > Streams [ 0 ] . Attached )
TNC - > Streams [ 0 ] . ReportDISC = TRUE ;
return ( 0 ) ;
}
// Have some data
ProcessMPSKPacket ( TNC , Message , bytes ) ; // Data may be for another port
return ( 0 ) ;
}
VOID ProcessMSPKCmd ( struct TNCINFO * TNC ) ;
VOID ProcessMSPKComment ( struct TNCINFO * TNC ) ;
VOID ProcessMSPKData ( struct TNCINFO * TNC ) ;
VOID ProcessMPSKPacket ( struct TNCINFO * TNC , char * Message , int Len )
{
char * MPTR = Message ;
/*
3 ) each text character transmitted by the client to the server ( for the Multipsk TX text editor ) must be preceded by the character CHR ( 25 ) or CHR ( 22 ) in the case of a special link ( KISS in Packet or Pax , for example ) .
4 ) each command string transmitted by the client to the server must be preceded by the character CHR ( 26 ) and finished by CHR ( 27 ) ,
5 ) each character effectively transmitted by Multipsk to the transceiver and transmitted to the client is preceded by the character CHR ( 28 ) ,
6 ) each character received by Multipsk and transmitted to the client is preceded by the character CHR ( 29 ) ,
7 ) each command string transmitted by the server to the client must be preceded by the character CHR ( 30 ) and finished by CHR ( 31 ) ,
8 ) all commands ( written in readable text ) will have an answer ( see further for details ) ,
9 ) each server comment ( Call ID or RS ID reception , switch to RX or to TX ) string transmitted by the server to the client must be preceded by a string : " CHR(23)RX CALL ID= " , " CHR(23)RX RS ID= " , " CHR(23)SWITCH=RX " , " CHR(23) SWITCH=TX " , and finished by CHR ( 24 ) .
10 ) each server command , for the transceiver control , transmitted by the server to the client must be preceded by the string " CHR(23) XCVR= " and finished by CHR ( 24 ) .
Data
End of TX ] ARQ FAE CQ [ End of TX ] ARQ FAE CQ [ End of TX ] call " THIS I[End of TX] end of link to GM8BPQ[End of TX] sounding " THIS WAS " [End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQFAE BEACON OH5RM Kouvola KP30JR
[ End of TX ] ARQ FAE selective callGM8BPQ DE OH5RM
[ Connection made with OH5RM ]
18103 but I have to go out to change antenna
[ End of connection with OH5RM ] FAE BEACON OH5RM Kouvola KP30JR
S " to GM8BPQ
10 : 23 : 55 AM Comment : SWITCH = RX
10 : 24 : 00 AM Comment : RX RS ID = 10 : 24 : 00 UTC ALE400 1609 Hz 0 MHz
10 : 24 : 19 AM Comment : RX RS ID = 10 : 24 : 19 UTC ALE400 1604 Hz 0 MHz
10 : 25 : 04 AM Comment : SWITCH = TX
10 : 25 : 07 AM Comment : SWITCH = RX
10 : 25 : 15 AM Comment : SWITCH = TX
: 30 : 22 AM Comment : SWITCH = RX
10 : 30 : 25 AM Comment : SWITCH = TX
10 : 30 : 27 AM Comment : SWITCH = RX
10 : 30 : 35 AM Comment : RX RS ID = 10 : 30 : 35 UTC ALE400 1598 Hz 0 MHz
*/
// Reuse the HAL CMD and Data Buffers to build messages from TCP stream
// See if sequence split over a packet boundary
if ( TNC - > CmdEsc = = 23 )
{
TNC - > CmdEsc = 0 ;
goto CommentEsc ;
}
if ( TNC - > CmdEsc = = 29 )
{
TNC - > CmdEsc = 0 ;
goto DataEsc ;
}
if ( TNC - > CmdEsc = = 30 )
{
TNC - > CmdEsc = 0 ;
goto CmdEsc ;
}
// No Split
while ( Len )
{
switch ( * ( MPTR + + ) )
{
case 29 : // Data Char
Len - - ;
DataEsc :
if ( Len )
{
TNC - > DataBuffer [ TNC - > DataLen + + ] = * MPTR ;
MPTR + + ;
Len - - ;
goto OuterLoop ;
}
TNC - > CmdEsc = 29 ;
if ( TNC - > DataLen )
ProcessMSPKData ( TNC ) ;
return ; // Nothing left
case 30 :
Len - - ;
CmdEsc :
while ( Len )
{
if ( * MPTR = = 31 ) // End of String
{
ProcessMSPKCmd ( TNC ) ;
TNC - > CmdLen = 0 ;
// Process any data left in buffer
MPTR + + ;
Len - - ;
goto OuterLoop ;
}
TNC - > CmdBuffer [ TNC - > CmdLen + + ] = * MPTR ;
MPTR + + ;
Len - - ;
}
TNC - > CmdEsc = 30 ;
return ; // Nothing left
case 23 : // Server Comment
Len - - ;
CommentEsc :
while ( Len )
{
if ( * MPTR = = 24 ) // End of String
{
// Process Comment
ProcessMSPKCmd ( TNC ) ;
TNC - > CmdLen = 0 ;
// Process any data left in buffer
MPTR + + ;
Len - - ;
goto OuterLoop ;
}
TNC - > CmdBuffer [ TNC - > CmdLen + + ] = * MPTR ;
MPTR + + ;
Len - - ;
}
TNC - > CmdEsc = 23 ;
return ; // Nothing left
default :
Len - - ;
}
OuterLoop : ;
}
if ( TNC - > DataLen )
ProcessMSPKData ( TNC ) ;
}
VOID ProcessMSPKCmd ( struct TNCINFO * TNC )
{
TNC - > CmdBuffer [ TNC - > CmdLen ] = 0 ;
if ( strcmp ( TNC - > CmdBuffer , " SWITCH=TX " ) = = 0 )
TNC - > MPSKInfo - > TX = TRUE ;
else
{
if ( strcmp ( TNC - > CmdBuffer , " SWITCH=RX " ) = = 0 )
{
TNC - > MPSKInfo - > TX = FALSE ;
// See if a command was queued while busy
if ( TNC - > CmdSet )
{
send ( TNC - > TCPSock , TNC - > CmdSet , strlen ( TNC - > CmdSet ) , 0 ) ;
free ( TNC - > CmdSet ) ;
TNC - > CmdSet = NULL ;
}
}
else
{
Debugprintf ( " MPSK CMD %s " , TNC - > CmdBuffer ) ;
if ( TNC - > InternalCmd )
{
PMSGWITHLEN buffptr = GetBuff ( ) ;
char * ptr = strstr ( TNC - > CmdBuffer , " OK " ) ;
if ( ptr )
* ( ptr + 2 ) = 0 ; // Convert OKn to OK for BBS Connect Script
TNC - > InternalCmd = FALSE ;
if ( buffptr )
{
buffptr - > Len = sprintf ( buffptr - > Data , " MPSK} %s \r " , TNC - > CmdBuffer ) ;
C_Q_ADD ( & TNC - > Streams [ 0 ] . PACTORtoBPQ_Q , buffptr ) ;
}
if ( strstr ( TNC - > CmdBuffer , " STOP_SELECTIVE_CALL_ARQ_FAE OK " ) )
TNC - > Streams [ 0 ] . Connecting = FALSE ;
}
}
}
}
VOID ProcessMSPKComment ( struct TNCINFO * TNC )
{
TNC - > CmdBuffer [ TNC - > CmdLen ] = 0 ;
Debugprintf ( " MPSK Comment %s " , TNC - > CmdBuffer ) ;
}
static int UnStuff ( UCHAR * inbuff , int len )
{
int i , txptr = 0 ;
UCHAR c ;
UCHAR * outbuff = inbuff ;
for ( i = 0 ; i < len ; i + + )
{
c = inbuff [ i ] ;
if ( c = = 0xc0 )
c = inbuff [ + + i ] - 0x20 ;
outbuff [ txptr + + ] = c ;
}
return txptr ;
}
VOID ProcessMSPKData ( struct TNCINFO * TNC )
{
PMSGWITHLEN buffptr ;
int Stream = 0 ;
struct STREAMINFO * STREAM = & TNC - > Streams [ 0 ] ;
char * ptr ;
int Len = TNC - > DataLen ;
TNC - > DataBuffer [ TNC - > DataLen ] = 0 ;
// Process Data
if ( STREAM - > Connected )
{
ptr = strstr ( TNC - > DataBuffer , " [End of connection " ) ;
if ( ptr )
{
// Disconnect
TNC - > DataLen = 0 ;
if ( STREAM - > DiscWhenAllSent )
return ; // Already notified
if ( STREAM - > Connecting )
{
// Report Connect Failed, and drop back to command mode
STREAM - > Connecting = FALSE ;
buffptr = GetBuff ( ) ;
if ( buffptr = = 0 ) return ; // No buffers, so ignore
buffptr - > Len = sprintf ( buffptr - > Data , " MPSK} Failure with %s \r " , STREAM - > RemoteCall ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
STREAM - > DiscWhenAllSent = 10 ;
return ;
}
// Release Session
STREAM - > Connecting = FALSE ;
STREAM - > Connected = FALSE ; // Back to Command Mode
STREAM - > ReportDISC = TRUE ; // Tell Node
STREAM - > Disconnecting = FALSE ;
STREAM - > DiscWhenAllSent = 10 ;
STREAM - > FramesOutstanding = 0 ;
return ;
}
// Pass to Application. Remove any transparency (hex 0xc0 used as an escape)
buffptr = GetBuff ( ) ;
if ( TNC - > DataBuffer [ TNC - > DataLen - 1 ] = = 0xc0 )
return ; // Last char is an escape, so wait for the escaped char to arrive
if ( buffptr )
{
if ( memchr ( TNC - > DataBuffer , 0xc0 , TNC - > DataLen ) )
TNC - > DataLen = UnStuff ( TNC - > DataBuffer , TNC - > DataLen ) ;
buffptr - > Len = TNC - > DataLen ;
memcpy ( buffptr - > Data , TNC - > DataBuffer , TNC - > DataLen ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
2024-11-05 21:03:15 +00:00
STREAM - > bytesRXed + = TNC - > DataLen ;
2022-08-28 09:35:46 +01:00
}
TNC - > DataLen = 0 ;
return ;
}
// Not Connected. We get various status messages, including Connection made,
// but they may be split across packets, or have more that one to a packet.
// I think they are all CR/LF terminated . No they aren't!
// Look for [] this seems to be what is important
DataLoop :
if ( memcmp ( TNC - > DataBuffer , " [End of TX] ARQ FAE CQ " , 22 ) = = 0 )
{
// Remove string from buffer
if ( Len = = 22 ) // Most Likely
{
TNC - > DataLen = 0 ;
return ;
}
TNC - > DataLen - = 22 ;
memmove ( TNC - > DataBuffer , & TNC - > DataBuffer [ 22 ] , Len - 21 ) ; //Copy Null
Len - = 22 ;
goto DataLoop ;
}
ptr = strchr ( TNC - > DataBuffer , ' [ ' ) ;
if ( ptr )
{
// Start of a significant Message
char * eptr = strchr ( TNC - > DataBuffer , ' ] ' ) ;
char CallFrom [ 20 ] ;
char * cptr ;
if ( eptr = = 0 )
return ; // wait for matching []
cptr = strstr ( TNC - > DataBuffer , " [Connection made with " ) ;
// TNC->DataLen -= LineLen;
// memmove(TNC->DataBuffer, &TNC->DataBuffer[LineLen], 1 + Len - LineLen); //Copy Null
// Len -= LineLen;
// goto DataLoop;
if ( cptr ) // Have a connection
{
// Connected
memcpy ( CallFrom , & cptr [ 22 ] , 18 ) ;
cptr = strchr ( CallFrom , ' ] ' ) ;
if ( cptr )
* cptr = 0 ;
if ( STREAM - > Connecting )
{
// Connect Complete
STREAM - > Connected = TRUE ;
STREAM - > Connecting = FALSE ;
STREAM - > ConnectTime = time ( NULL ) ;
2024-11-05 21:03:15 +00:00
STREAM - > bytesRXed = STREAM - > bytesTXed = 0 ;
2022-08-28 09:35:46 +01:00
buffptr = GetBuff ( ) ;
if ( buffptr )
{
buffptr - > Len = sprintf ( buffptr - > Data , " *** Connected to %s \r " , CallFrom ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
}
}
else
{
// Incoming. Look for a free Stream
STREAM - > Connected = TRUE ;
STREAM - > ConnectTime = time ( NULL ) ;
2024-11-05 21:03:15 +00:00
STREAM - > bytesRXed = STREAM - > bytesTXed = 0 ;
2022-08-28 09:35:46 +01:00
UpdateMH ( TNC , CallFrom , ' + ' , ' I ' ) ;
ProcessIncommingConnect ( TNC , CallFrom , Stream , FALSE ) ;
if ( HFCTEXTLEN )
{
if ( HFCTEXTLEN > 1 )
SendData ( TNC , HFCTEXT , HFCTEXTLEN ) ;
}
else
{
if ( FULL_CTEXT )
{
int Len = CTEXTLEN , CTPaclen = 50 ;
int Next = 0 ;
while ( Len > CTPaclen ) // CTEXT Paclen
{
SendData ( TNC , & CTEXTMSG [ Next ] , CTPaclen ) ;
Next + = CTPaclen ;
Len - = CTPaclen ;
}
SendData ( TNC , & CTEXTMSG [ Next ] , Len ) ;
}
}
}
}
}
// Doesnt contain [ - just discard
TNC - > DataLen = 0 ;
Debugprintf ( TNC - > DataBuffer ) ;
return ;
}
/*
buffptr = GetBuff ( ) ;
if ( buffptr = = 0 ) return ; // No buffers, so ignore
buffptr [ 1 ] = RXHeader - > DataLength ;
memcpy ( & buffptr [ 2 ] , Message , RXHeader - > DataLength ) ;
C_Q_ADD ( & STREAM - > PACTORtoBPQ_Q , buffptr ) ;
return ;
return ;
case ' d ' : // Disconnected
case ' C ' :
// Connect. Can be Incoming or Outgoing
// "*** CONNECTED To Station [CALLSIGN]" When the other station starts the connection
// "*** CONNECTED With [CALLSIGN]" When we started the connection
*/
VOID SendData ( struct TNCINFO * TNC , char * Msg , int MsgLen )
{
// Preceed each data byte with 25 (decimal)
char * NewMsg = malloc ( MsgLen * 4 ) ;
int n ;
UCHAR c ;
int ExtraLen = 0 ;
char * ptr = NewMsg ;
char * inptr = Msg ;
SOCKET sock = TNCInfo [ MasterPort [ TNC - > Port ] ] - > TCPSock ;
2024-11-05 21:03:15 +00:00
TNC - > Streams [ 0 ] . bytesTXed + = MsgLen ;
2022-08-28 09:35:46 +01:00
for ( n = 0 ; n < MsgLen ; n + + )
{
* ( ptr + + ) = 25 ;
c = * inptr + + ;
if ( c < 0x20 | | c = = 0xc0 )
{
if ( c ! = 0x0d )
{
* ptr + + = 0x0c0 ;
* ( ptr + + ) = 25 ;
* ptr + + = c + 0x20 ;
ExtraLen + = 2 ;
continue ;
}
}
* ptr + + = c ;
}
send ( sock , NewMsg , MsgLen * 2 + ExtraLen , 0 ) ;
free ( NewMsg ) ;
}
VOID TidyClose ( struct TNCINFO * TNC , int Stream )
{
char Command [ 80 ] ;
int len ;
len = sprintf ( Command , " %cSTOP_SELECTIVE_CALL_ARQ_FAE \x1b " , ' \x1a ' ) ;
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Command ) ; // Savde till not transmitting
else
send ( TNC - > TCPSock , Command , len , 0 ) ;
}
VOID ForcedClose ( struct TNCINFO * TNC , int Stream )
{
TidyClose ( TNC , Stream ) ; // I don't think Hostmode has a DD
}
VOID CloseComplete ( struct TNCINFO * TNC , int Stream )
{
char Cmd [ 80 ] ;
int Len ;
sprintf ( Cmd , " %d SCANSTART 15 " , TNC - > Port ) ;
2023-05-16 16:40:12 +01:00
Rig_Command ( ( TRANSPORTENTRY * ) - 1 , Cmd ) ;
2022-08-28 09:35:46 +01:00
Cmd [ 0 ] = 0 ;
if ( TNC - > MPSKInfo - > DefaultMode [ 0 ] )
sprintf ( Cmd , " %cDIGITAL MODE %s \x1b " , ' \x1a ' , TNC - > MPSKInfo - > DefaultMode ) ;
if ( TNC - > MPSKInfo - > Beacon )
sprintf ( Cmd , " %s%cBEACON_ARQ_FAE \x1b " , Cmd , ' \x1a ' ) ;
Len = strlen ( Cmd ) ;
if ( Len )
{
if ( TNC - > MPSKInfo - > TX )
TNC - > CmdSet = TNC - > CmdSave = _strdup ( Cmd ) ; // Savde till not transmitting
else
send ( TNC - > TCPSock , Cmd , Len , 0 ) ;
}
}