Files
2021-02-28 22:28:59 +01:00

581 lines
14 KiB
C

/*
* "Roadshow" Amiga TCP/IP stack
*
* :ts=4
*
* Copyright © 2001-2019 by Olaf Barthel. All Rights Reserved.
*/
/*****************************************************************************/
#define __USE_OLD_TIMEVAL__
#include <devices/timer.h>
/****************************************************************************/
#include <dos/dosextens.h>
#include <dos/dosasl.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <dos/stdio.h>
#include <exec/memory.h>
#include <devices/sana2.h>
/*****************************************************************************/
#include <clib/alib_protos.h>
/*****************************************************************************/
#define __NOLIBBASE__
#define __NOGLOBALIFACE__
#define __USE_INLINE__
/*****************************************************************************/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/timer.h>
/*****************************************************************************/
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
/****************************************************************************/
#include "Online_rev.h"
TEXT Version[] = VERSTAG;
/****************************************************************************/
#include "macros.h"
/****************************************************************************/
/*#define DEBUG*/
#include "assert.h"
/****************************************************************************/
#if defined(__amigaos4__)
#define VAR_ARGS __attribute__((linearvarargs))
#else
#define VAR_ARGS
#endif /* __amigaos4__ */
/****************************************************************************/
extern struct Library * SysBase;
extern struct Library * DOSBase;
/****************************************************************************/
#if defined(__amigaos4__)
extern struct ExecIFace * IExec;
extern struct DOSIFace * IDOS;
#endif /* __amigaos4__ */
/****************************************************************************/
struct MsgPort * TimePort;
struct timerequest * TimeRequest;
BOOL TimeRequestPending;
LONG Timeout;
/****************************************************************************/
struct RDArgs * read_args;
/****************************************************************************/
struct MsgPort * NetPort;
struct IOSana2Req * NetRequest;
struct IOSana2Req * NetEventRequest;
BOOL NetEventRequestPending;
/****************************************************************************/
STRPTR NetDeviceName;
LONG NetDeviceUnit;
/****************************************************************************/
STRPTR get_io_error_string(LONG error, UBYTE *buffer);
STRPTR get_wire_error_string(LONG error, UBYTE *buffer);
VOID VAR_ARGS local_sprintf(STRPTR buffer, STRPTR formatString, ...);
VOID cleanup(void);
BOOL setup(void);
/****************************************************************************/
/* Return a descriptive text for an I/O error code returned by a
* SANA-II device.
*/
STRPTR
get_io_error_string(LONG error,UBYTE * buffer)
{
STATIC struct { LONG val; STRPTR str; } tab[] =
{
{ IOERR_OPENFAIL, "Device/unit failed to open" },
{ IOERR_ABORTED, "Request terminated early" },
{ IOERR_NOCMD, "Command not supported by device" },
{ IOERR_BADLENGTH, "Not a valid length" },
{ IOERR_BADADDRESS, "Invalid address" },
{ IOERR_UNITBUSY, "Device opens OK, but requested unit is busy" },
{ IOERR_SELFTEST, "Hardware failed self-test" },
{ S2ERR_NO_RESOURCES, "Resource allocation failure" },
{ S2ERR_BAD_ARGUMENT, "Bad argument" },
{ S2ERR_BAD_STATE, "Inappropriate state" },
{ S2ERR_BAD_ADDRESS, "Bad address" },
{ S2ERR_MTU_EXCEEDED, "Maximum transmission unit exceeded" },
{ S2ERR_NOT_SUPPORTED, "Command not supported by hardware" },
{ S2ERR_SOFTWARE, "Software error detected" },
{ S2ERR_OUTOFSERVICE, "Driver is offline" },
{ S2ERR_TX_FAILURE, "Transmission attempt failed" }
};
LONG i,n;
n = -1;
for(i = 0 ; i < (LONG)NUM_ENTRIES(tab) ; i++)
{
if(tab[i].val == error)
{
n = i;
break;
}
}
if(n != -1)
{
strcpy(buffer,tab[n].str);
}
else
{
if(error < 0)
local_sprintf(buffer,"Unknown I/O error %ld",error);
else
local_sprintf(buffer,"Unknown SANA-II error %ld",error);
}
return(buffer);
}
/****************************************************************************/
/* Return a descriptive text for an wire error code returned
* by a SANA-II device.
*/
STRPTR
get_wire_error_string(LONG error,UBYTE * buffer)
{
STATIC struct { LONG val; STRPTR str; } tab[] =
{
{ S2WERR_GENERIC_ERROR, "No specific information available" },
{ S2WERR_NOT_CONFIGURED, "Unit is not configured" },
{ S2WERR_UNIT_ONLINE, "Unit is currently online" },
{ S2WERR_UNIT_OFFLINE, "Unit is currently offline" },
{ S2WERR_ALREADY_TRACKED, "Protocol is already tracked" },
{ S2WERR_NOT_TRACKED, "Protocol is not tracked" },
{ S2WERR_BUFF_ERROR, "Buffer management function returned an error" },
{ S2WERR_SRC_ADDRESS, "Source address problem" },
{ S2WERR_DST_ADDRESS, "Destination address problem" },
{ S2WERR_BAD_BROADCAST, "Broadcast address problem" },
{ S2WERR_BAD_MULTICAST, "Multicast address problem" },
{ S2WERR_MULTICAST_FULL, "Multicast address list is full" },
{ S2WERR_BAD_EVENT, "Unsupported event class" },
{ S2WERR_BAD_STATDATA, "StatData failed sanity check" },
{ S2WERR_IS_CONFIGURED, "Attempted to configure twice" },
{ S2WERR_NULL_POINTER, "NULL pointer detected" },
{ S2WERR_TOO_MANY_RETRIES, "Transmission failed - too many retries" },
{ S2WERR_RCVREL_HDW_ERR, "Driver fixable hardware error" }
};
LONG i,n;
n = -1;
for(i = 0 ; i < (LONG)NUM_ENTRIES(tab) ; i++)
{
if(tab[i].val == error)
{
n = i;
break;
}
}
if(n != -1)
strcpy(buffer,tab[n].str);
else
local_sprintf(buffer,"Unknown wire error %ld",error);
return(buffer);
}
/****************************************************************************/
VOID VAR_ARGS
local_sprintf(STRPTR buffer, STRPTR formatString,...)
{
va_list varArgs;
#if defined(__amigaos4__)
{
va_startlinear(varArgs,formatString);
RawDoFmt(formatString,va_getlinearva(varArgs, APTR),NULL,buffer);
va_end(varArgs);
}
#else
{
va_start(varArgs,formatString);
RawDoFmt(formatString,varArgs,(VOID (*)())"\x16\xC0\x4E\x75",buffer);
va_end(varArgs);
}
#endif /* __amigaos4__ */
}
/****************************************************************************/
VOID
cleanup(void)
{
if(NetEventRequestPending)
{
if(CheckIO((struct IORequest *)NetEventRequest) == BUSY)
AbortIO((struct IORequest *)NetEventRequest);
WaitIO((struct IORequest *)NetEventRequest);
NetEventRequestPending = FALSE;
}
if(NetRequest != NULL)
{
if(NetRequest->ios2_Req.io_Device != NULL)
CloseDevice((struct IORequest *)NetRequest);
DeleteIORequest((struct IORequest *)NetRequest);
NetRequest = NULL;
}
if(NetPort != NULL)
{
DeleteMsgPort(NetPort);
NetPort = NULL;
}
if(TimeRequestPending)
{
if(CheckIO((struct IORequest *)TimeRequest) == BUSY)
AbortIO((struct IORequest *)TimeRequest);
WaitIO((struct IORequest *)TimeRequest);
TimeRequestPending = FALSE;
}
if(TimeRequest != NULL)
{
if(TimeRequest->tr_node.io_Device != NULL)
CloseDevice((struct IORequest *)TimeRequest);
DeleteIORequest((struct IORequest *)TimeRequest);
TimeRequest = NULL;
}
if(TimePort != NULL)
{
DeleteMsgPort(TimePort);
TimePort = NULL;
}
if(read_args != NULL)
{
FreeArgs(read_args);
read_args = NULL;
}
}
/****************************************************************************/
BOOL
setup(void)
{
struct
{
STRPTR Name;
LONG * Unit;
LONG * Timeout;
} args_list;
STRPTR full_path_name = NULL;
BOOL success = FALSE;
LONG error;
if(SysBase->lib_Version < 36)
goto out;
memset(&args_list,0,sizeof(args_list));
read_args = ReadArgs("NAME/A,UNIT/N,TIMEOUT/N",(LONG *)&args_list,NULL);
if(read_args == NULL)
{
PrintFault(IoErr(),"Online");
goto out;
}
NetDeviceName = args_list.Name;
if(args_list.Unit != NULL)
NetDeviceUnit = (*args_list.Unit);
if(args_list.Timeout != NULL)
Timeout = (*args_list.Timeout);
TimePort = CreateMsgPort();
if(TimePort == NULL)
{
Printf("%s: Could not create timer message port.\n", "Online");
goto out;
}
TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(*TimeRequest));
if(TimeRequest == NULL)
{
Printf("%s: Could not create timer I/O request.\n", "Online");
goto out;
}
if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimeRequest,0) != OK)
{
Printf("%s: Could not open 'timer.device'.\n", "Online");
goto out;
}
NetPort = CreateMsgPort();
if(NetPort == NULL)
{
Printf("%s: Could not create net I/O message port.\n", "Online");
goto out;
}
NetRequest = (struct IOSana2Req *)CreateIORequest(NetPort,sizeof(*NetRequest));
NetEventRequest = (struct IOSana2Req *)CreateIORequest(NetPort,sizeof(*NetEventRequest));
if(NetRequest == NULL || NetEventRequest == NULL)
{
Printf("%s: Could not create net I/O request.\n", "Online");
goto out;
}
error = OpenDevice(NetDeviceName,NetDeviceUnit,(struct IORequest *)NetRequest,0);
if(error == IOERR_OPENFAIL && FilePart(NetDeviceName) == NetDeviceName)
{
STRPTR prefix = "DEVS:Networks/";
full_path_name = AllocVec(strlen(prefix)+strlen(NetDeviceName)+1,MEMF_ANY);
if(full_path_name == NULL)
{
PrintFault(ERROR_NO_FREE_STORE,"Online");
goto out;
}
local_sprintf(full_path_name,"%s%s",prefix,NetDeviceName);
error = OpenDevice(full_path_name,NetDeviceUnit,(struct IORequest *)NetRequest,0);
}
if(error != OK)
{
UBYTE io_error_string[100];
Printf("%s: Could not open '%s', unit %ld (%ld, %s).\n",
"Online",NetDeviceName,NetDeviceUnit,error,get_io_error_string(error,io_error_string));
goto out;
}
(*NetEventRequest) = (*NetRequest);
NetEventRequest->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
success = TRUE;
out:
if(full_path_name != NULL)
FreeVec(full_path_name);
return(success);
}
/****************************************************************************/
/****** ROADSHOW/ONLINE ******************************************************
*
* NAME
* Online - Attempt to switch a network device driver online
*
* FORMAT
* Online <Device driver name> [UNIT=<Unit number>] [TIMEOUT=<Seconds>]
*
* TEMPLATE
* NAME/A,UNIT/N,TIMEOUT/N
*
* PATH
* C:Online
*
* FUNCTION
* The "Online" command attempts to switch a network device driver into
* online state. This may be necessary after having taken that driver
* offline first, such as to perform hardware diagnostics.
*
* OPTIONS
* NAME/A
* The name of the SANA-II standard compliant network device
* driver, e.g. "ariadne.device".
*
* UNIT/N
* The number of the device unit, e.g. 0 for the first network
* interface managed by the device driver, 1 for the second,
* etc. The unit number defaults to 0.
*
* TIMEOUT/N
* How many seconds to wait for the device unit to come back
* online before the attempt is aborted. The timeout defaults
* to 0, which means that the "Online" command will wait forever
* for the the device unit to come online.
*
* NOTES
* You may use the "Break" command or press the [Ctrl]+C keys to
* abort the "Online" command while it is waiting for the device
* unit to come online.
*
* When the "Online" command exits, the return code will indicate
* error, warning or success which you may use in script files
* to test for the outcome of the process.
*
* Some device drivers will return an error in case the device
* unit is already online and operational instead of just stating
* that the respective unit is already online. You might want to
* examine the device driver's performance before you write scripts
* which depend upon a specific behaviour.
*
* EXAMPLES
* Take the "a2065.device" online again, if possible; wait for up
* to 5 seconds for it be online:
*
* 1> Online a2065.device timeout 5
*
* SEE ALSO
* Offline
*
******************************************************************************
*/
int
main(int argc,char **argv)
{
int return_code = RETURN_ERROR;
ULONG time_mask;
ULONG net_mask;
ULONG signal_mask;
ULONG signals;
LONG error;
if(!setup())
goto out;
NetEventRequest->ios2_Req.io_Command = S2_ONEVENT;
NetEventRequest->ios2_WireError = S2EVENT_ONLINE;
SendIO((struct IORequest *)NetEventRequest);
NetEventRequestPending = TRUE;
if(Timeout > 0)
{
TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
TimeRequest->tr_time.tv_secs = Timeout * 60;
TimeRequest->tr_time.tv_micro = 0;
SendIO((struct IORequest *)TimeRequest);
TimeRequestPending = TRUE;
}
NetRequest->ios2_Req.io_Command = S2_ONLINE;
error = DoIO((struct IORequest *)NetRequest);
if(error == S2WERR_UNIT_ONLINE)
{
return_code = RETURN_OK;
goto out;
}
if(error != 0)
{
UBYTE io_error_string[100];
Printf("%s: Could not switch '%s', unit %ld online (%ld, %s).\n",
"Online",NetDeviceName,NetDeviceUnit,error,get_io_error_string(error,io_error_string));
goto out;
}
time_mask = 1UL << TimePort->mp_SigBit;
net_mask = 1UL << NetPort->mp_SigBit;
signal_mask = SIGBREAKF_CTRL_C | time_mask | net_mask;
signals = 0;
while(TRUE)
{
if(signals == 0)
signals = Wait(signal_mask);
else
signals |= SetSignal(0,signal_mask) & signal_mask;
if(signals & SIGBREAKF_CTRL_C)
{
PrintFault(ERROR_BREAK, "Online");
return_code = RETURN_WARN;
break;
}
if(signals & net_mask)
{
if(NetEventRequestPending && CheckIO((struct IORequest *)NetEventRequest) != BUSY)
{
WaitIO((struct IORequest *)NetEventRequest);
NetEventRequestPending = FALSE;
if(NetEventRequest->ios2_Req.io_Error == 0 && (NetEventRequest->ios2_WireError & S2EVENT_ONLINE))
{
return_code = RETURN_OK;
break;
}
}
signals &= ~net_mask;
}
if(signals & time_mask)
{
Printf("%s: '%s', unit %ld could not be switched online (timeout).\n",
"Online",NetDeviceName,NetDeviceUnit);
return_code = RETURN_WARN;
break;
}
}
out:
cleanup();
return(return_code);
}