407 lines
9.0 KiB
C
407 lines
9.0 KiB
C
|
/*
|
||
|
Copyright 2001-2015 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
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Implements the DOS register based API.
|
||
|
|
||
|
// Called via an assmbler glue that puts registers into C variables.
|
||
|
|
||
|
#define _CRT_SECURE_NO_DEPRECATE
|
||
|
|
||
|
#pragma data_seg("_BPQDATA")
|
||
|
|
||
|
#include "time.h"
|
||
|
#include "stdio.h"
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
#include "compatbits.h"
|
||
|
|
||
|
#include "CHeaders.h"
|
||
|
|
||
|
extern QCOUNT;
|
||
|
extern BPQVECSTRUC BPQHOSTVECTOR[];
|
||
|
extern int MAJORVERSION;
|
||
|
extern int MINORVERSION;
|
||
|
extern char pgm[256]; // Uninitialised so per process
|
||
|
|
||
|
VOID PostDataAvailable(TRANSPORTENTRY * Session);
|
||
|
DllExport int APIENTRY SendMsg(int stream, char * msg, int len);
|
||
|
DllExport int APIENTRY AllocateStream(int stream);
|
||
|
DllExport int APIENTRY SendRaw(int port, char * msg, int len);
|
||
|
DllExport time_t APIENTRY GetRaw(int stream, char * msg, int * len, int * count);
|
||
|
VOID SENDNODESMSG();
|
||
|
|
||
|
int BTLENGTH;
|
||
|
char BTEXTFLD[256];
|
||
|
int REALTIMETICKS;
|
||
|
|
||
|
VOID CHOSTAPI(ULONG * pEAX, ULONG * pEBX, ULONG * pECX, ULONG * pEDX, VOID ** pESI, VOID ** pEDI)
|
||
|
{
|
||
|
ULONG EAX = *pEAX;
|
||
|
ULONG EBX = *pEBX;
|
||
|
ULONG ECX = *pECX;
|
||
|
ULONG EDX = *pEDX;
|
||
|
VOID * ESI = *pESI;
|
||
|
VOID * EDI = *pEDI;
|
||
|
|
||
|
int Command;
|
||
|
int Stream;
|
||
|
int n;
|
||
|
int Temp;
|
||
|
PBPQVECSTRUC HostVec;
|
||
|
TRANSPORTENTRY * Session;
|
||
|
|
||
|
/*
|
||
|
; COMMANDS SUPPORTED ARE
|
||
|
;
|
||
|
; AH = 0 Get node/switch version number and description. On return
|
||
|
; AH = major version number and AL = minor version number,
|
||
|
; and user's buffer pointed to by ES:ESI is set to the text
|
||
|
; string normally output by the USERS command, eg:
|
||
|
; "G8BPQ Packet Switch Version 4.01 Dev". CX is set to the
|
||
|
; length of the text string.
|
||
|
;
|
||
|
;
|
||
|
; AH = 1 Set application mask to value in DL (or even DX if 16
|
||
|
; applications are ever to be supported).
|
||
|
;
|
||
|
; Set application flag(s) to value in CL (or CX).
|
||
|
; whether user gets connected/disconnected messages issued
|
||
|
; by the node etc.
|
||
|
;
|
||
|
;
|
||
|
; AH = 2 Send frame in ES:ESI (length CX)
|
||
|
;
|
||
|
;
|
||
|
; AH = 3 Receive frame into buffer at ES:ESI, length of frame returned
|
||
|
; in CX. BX returns the number of outstanding frames still to
|
||
|
; be received (ie. after this one) or zero if no more frames
|
||
|
; (ie. this is last one).
|
||
|
;
|
||
|
;
|
||
|
;
|
||
|
; AH = 4 Get stream status. Returns:
|
||
|
;
|
||
|
; CX = 0 if stream disconnected or CX = 1 if stream connected
|
||
|
; DX = 0 if no change of state since last read, or DX = 1 if
|
||
|
; the connected/disconnected state has changed since
|
||
|
; last read (ie. delta-stream status).
|
||
|
;
|
||
|
;
|
||
|
;
|
||
|
; AH = 6 Session control.
|
||
|
;
|
||
|
; CX = 0 Conneect - _APPLMASK in DL
|
||
|
; CX = 1 connect
|
||
|
; CX = 2 disconnect
|
||
|
; CX = 3 return user to node
|
||
|
;
|
||
|
;
|
||
|
; AH = 7 Get buffer counts for stream. Returns:
|
||
|
;
|
||
|
; AX = number of status change messages to be received
|
||
|
; BX = number of frames queued for receive
|
||
|
; CX = number of un-acked frames to be sent
|
||
|
; DX = number of buffers left in node
|
||
|
; SI = number of trace frames queued for receive
|
||
|
;
|
||
|
;AH = 8 Port control/information. Called with a stream number
|
||
|
; in AL returns:
|
||
|
;
|
||
|
; AL = Radio port on which channel is connected (or zero)
|
||
|
; AH = SESSION TYPE BITS
|
||
|
; BX = L2 paclen for the radio port
|
||
|
; CX = L2 maxframe for the radio port
|
||
|
; DX = L4 window size (if L4 circuit, or zero)
|
||
|
; ES:EDI = CALLSIGN
|
||
|
|
||
|
;AH = 9 Fetch node/application callsign & alias. AL = application
|
||
|
; number:
|
||
|
;
|
||
|
; 0 = node
|
||
|
; 1 = BBS
|
||
|
; 2 = HOST
|
||
|
; 3 = SYSOP etc. etc.
|
||
|
;
|
||
|
; Returns string with alias & callsign or application name in
|
||
|
; user's buffer pointed to by ES:ESI length CX. For example:
|
||
|
;
|
||
|
; "WORCS:G8TIC" or "TICPMS:G8TIC-10".
|
||
|
;
|
||
|
;
|
||
|
; AH = 10 Unproto transmit frame. Data pointed to by ES:ESI, of
|
||
|
; length CX, is transmitted as a HDLC frame on the radio
|
||
|
; port (not stream) in AL.
|
||
|
;
|
||
|
;
|
||
|
; AH = 11 Get Trace (RAW Data) Frame into ES:EDI,
|
||
|
; Length to CX, Timestamp to AX
|
||
|
;
|
||
|
;
|
||
|
; AH = 12 Update Switch. At the moment only Beacon Text may be updated
|
||
|
; DX = Function
|
||
|
; 1=update BT. ES:ESI, Len CX = Text
|
||
|
; 2=kick off nodes broadcast
|
||
|
;
|
||
|
; AH = 14 Internal Interface for IP Router
|
||
|
;
|
||
|
; Send frame - to NETROM L3 if DL=0
|
||
|
; to L2 Session if DL<>0
|
||
|
;
|
||
|
;
|
||
|
; AH = 15 Get interval timer
|
||
|
;
|
||
|
|
||
|
*/
|
||
|
|
||
|
Command = (EAX & 0xFFFF) >> 8;
|
||
|
|
||
|
Stream = (EAX & 0xFF);
|
||
|
n = Stream - 1; // API Numbers Streams 1-64
|
||
|
|
||
|
if (n < 0 || n > 63)
|
||
|
n = 64;
|
||
|
|
||
|
HostVec = &BPQHOSTVECTOR[n];
|
||
|
Session = HostVec->HOSTSESSION;
|
||
|
|
||
|
switch (Command)
|
||
|
{
|
||
|
case 0: // Check Loaded/Get Version
|
||
|
|
||
|
EAX = ('P' << 8) | 'B';
|
||
|
EBX = ('Q' << 8) | ' ';
|
||
|
|
||
|
EDX = (MAJORVERSION << 8) | MINORVERSION;
|
||
|
break;
|
||
|
|
||
|
case 1: // Set Appl mAsk
|
||
|
|
||
|
HostVec->HOSTAPPLMASK = EDX; // APPL MASK
|
||
|
HostVec->HOSTAPPLFLAGS = (UCHAR)ECX; // APPL FLAGS
|
||
|
|
||
|
// If either is non-zero, set allocated and Process. This gets round problem with
|
||
|
// stations that don't call allocate stream
|
||
|
|
||
|
if (ECX || EBX)
|
||
|
{
|
||
|
HostVec->HOSTFLAGS |= 0x80; // SET ALLOCATED BIT
|
||
|
HostVec->STREAMOWNER = GetCurrentProcessId();
|
||
|
|
||
|
// Set Program Name
|
||
|
|
||
|
memcpy(&HostVec->PgmName, pgm, 31);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2: // Send Frame
|
||
|
|
||
|
// ES:ESI = MESSAGE, CX = LENGTH, BX = VECTOR
|
||
|
|
||
|
EAX = SendMsg(Stream, ESI, ECX);
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
|
||
|
// AH = 3 Receive frame into buffer at ES:EDI, length of frame returned
|
||
|
// in CX. BX returns the number of outstanding frames still to
|
||
|
// be received (ie. after this one) or zero if no more frames
|
||
|
// (ie. this is last one).
|
||
|
|
||
|
EAX = GetMsg(Stream, EDI, &ECX, &EBX);
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
|
||
|
// AH = 4 Get stream status. Returns:
|
||
|
// CX = 0 if stream disconnected or CX = 1 if stream connected
|
||
|
// DX = 0 if no change of state since last read, or DX = 1 if
|
||
|
// the connected/disconnected state has changed since
|
||
|
// last read (ie. delta-stream status).
|
||
|
|
||
|
ECX = EDX = 0;
|
||
|
|
||
|
if (HostVec->HOSTFLAGS & 3) //STATE CHANGE BITS
|
||
|
EDX = 1;
|
||
|
|
||
|
if (Session)
|
||
|
ECX = 1;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 5:
|
||
|
|
||
|
// AH = 5 Ack stream status change
|
||
|
|
||
|
HostVec->HOSTFLAGS &= 0xFC; // Clear Chnage Bits
|
||
|
break;
|
||
|
|
||
|
case 6:
|
||
|
|
||
|
// AH = 6 Session control.
|
||
|
|
||
|
// CX = 0 Conneect - APPLMASK in DL
|
||
|
// CX = 1 connect
|
||
|
// CX = 2 disconnect
|
||
|
// CX = 3 return user to node
|
||
|
|
||
|
SessionControl(Stream, ECX, EDX);
|
||
|
break;
|
||
|
|
||
|
case 7:
|
||
|
|
||
|
// AH = 7 Get buffer counts for stream. Returns:
|
||
|
|
||
|
// AX = number of status change messages to be received
|
||
|
// BX = number of frames queued for receive
|
||
|
// CX = number of un-acked frames to be sent
|
||
|
// DX = number of buffers left in node
|
||
|
// SI = number of trace frames queued for receive
|
||
|
|
||
|
|
||
|
ECX = 0; // unacked frames
|
||
|
EDX = QCOUNT;
|
||
|
|
||
|
ESI = (void *)MONCount(Stream);
|
||
|
EBX = RXCount(Stream);
|
||
|
ECX = TXCount(Stream);
|
||
|
|
||
|
EAX = 0; // Is this right ???
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
|
||
|
// AH = 8 Port control/information. Called with a stream number
|
||
|
// in AL returns:
|
||
|
//
|
||
|
// AL = Radio port on which channel is connected (or zero)
|
||
|
// AH = SESSION TYPE BITS
|
||
|
// BX = L2 paclen for the radio port
|
||
|
// CX = L2 maxframe for the radio port
|
||
|
// DX = L4 window size (if L4 circuit, or zero)
|
||
|
// ES:EDI = CALLSIGN
|
||
|
|
||
|
|
||
|
GetConnectionInfo(Stream, EDI, &EAX, &Temp, &EBX, &ECX, &EDX); // Return the Secure Session Flag rather than not connected
|
||
|
EAX |= Temp <<8;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 9:
|
||
|
|
||
|
// Not Implemented
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 10:
|
||
|
|
||
|
// AH = 10 Unproto transmit frame. Data pointed to by ES:ESI, of
|
||
|
// length CX, is transmitted as a HDLC frame on the radio
|
||
|
// port (not stream) in AL.
|
||
|
|
||
|
EAX = SendRaw(EAX, ESI, ECX);
|
||
|
return;
|
||
|
|
||
|
case 11:
|
||
|
|
||
|
// AH = 11 Get Trace (RAW Data) Frame into ES:EDI,
|
||
|
// Length to CX, Timestamp to AX
|
||
|
|
||
|
EAX = GetRaw(Stream, EDI, &ECX, &EBX);
|
||
|
break;
|
||
|
|
||
|
case 12:
|
||
|
|
||
|
// Update Switch
|
||
|
|
||
|
if (EDX == 2)
|
||
|
{
|
||
|
SENDNODESMSG();
|
||
|
break;
|
||
|
}
|
||
|
if (EDX == 2)
|
||
|
{
|
||
|
// UPDATE BT
|
||
|
|
||
|
BTLENGTH = ECX;
|
||
|
memcpy(BTEXTFLD, ESI, ECX + 7);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 13:
|
||
|
|
||
|
// BPQALLOC
|
||
|
|
||
|
// AL = 0 = Find Free
|
||
|
// AL != 0 Alloc or Release
|
||
|
|
||
|
if (EAX == 0)
|
||
|
{
|
||
|
EAX = FindFreeStream();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (ECX == 1) // Allocate
|
||
|
{
|
||
|
EAX = AllocateStream(Stream);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DeallocateStream(Stream);
|
||
|
break;
|
||
|
|
||
|
case 14:
|
||
|
|
||
|
// AH = 14 Internal Interface for IP Router
|
||
|
|
||
|
// Send frame - to NETROM L3 if DL=0
|
||
|
// to L2 Session if DL<>0
|
||
|
|
||
|
break; // Shouldn't be needed
|
||
|
|
||
|
case 15:
|
||
|
|
||
|
// GETTIME
|
||
|
|
||
|
EAX = REALTIMETICKS;
|
||
|
EBX = 0;
|
||
|
|
||
|
#ifdef EXCLUDEBITS
|
||
|
|
||
|
EBX = (ULONG)ExcludeList;
|
||
|
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
*pEAX = EAX;
|
||
|
*pEBX = EBX;
|
||
|
*pECX = ECX;
|
||
|
*pEDX = EDX;
|
||
|
*pESI = ESI;
|
||
|
*pEDI = EDI;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|