home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 3
/
Meeting_Pearls_III.iso
/
Pearls
/
tcp
/
Networking
/
Sana-II
/
spar372.lha
/
Sources
/
Spar_funcs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-18
|
18KB
|
575 lines
/*
** $Source: dh1:network/parnet/Sana2/Sources/spar_funcs.c,v $
** $State: Exp $
** $Revision: 37.2 $
** $Date: 93/12/17 23:12:43 $
** $Author: S.A.Pechler $
**
** Amiga SANA-II Example PARnet device driver.
**
** SPAR code.
**
** Based on the Amiga SANA-II Example SLIP device driver code by bj,
** which is (C) Copyright 1992 Commodore-Amiga, Inc.
** the rhslip.device by Olaf Seibert <rhialto@mbfys.kun.nl>, and on
** the agnet.device code by ppessi <Pekka.Pessi@hut.fi>, which is
** Copyright (c) 1993 AmiTCP/IP Group,
** Helsinki University of Technology, Finland.
** All rights reserved.
**
*/
#include "device_protos.h"
struct IntuitionBase *IntuitionBase=NULL;
extern int atoi(const char *); /* From stdlib.h */
#ifdef DEBUG
#include "spar_debug.h"
struct Window *DebWin1=NULL;
struct IOStdReq *DebReq=NULL;
struct MsgPort *DebPort=NULL;
# ifdef __STDC__
# include <stdarg.h>
extern int vsprintf(char *, const char *, va_list); /* from stdio.h */
void LogMessage(char *fmt, ...)
{
va_list args;
# else
# include <varargs.h>
void LogMessage(va_alist)
va_dcl
{
char *fmt;
va_list args;
# endif
char DebugText[128];
#ifdef __STDC__
va_start(args, fmt);
#else
va_start(args);
fmt = va_arg(args, char *);
#endif
vsprintf(DebugText,fmt,args);
if(DebReq && DebReq->io_Device)
{
DebReq->io_Command=CMD_WRITE;
DebReq->io_Data=(APTR)DebugText;
DebReq->io_Length=-1L;
DoIO((struct IORequest *)DebReq);
}
va_end(args);
}
void initsyslog(void)
{
if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37L))
{
DebWin1=OpenWindow(&DebugWin);
if(DebPort=CreateMsgPort())
if(DebReq=CreateIORequest(DebPort,sizeof(struct IOStdReq)))
{
DebReq->io_Data=(APTR) DebWin1;
DebReq->io_Length= sizeof(struct Window);
OpenDevice("console.device",0, (struct IORequest *)DebReq, 0);
}
}
}
void uninitsyslog(void)
{
AbortIO((struct IORequest *)DebReq);
WaitIO((struct IORequest *)DebReq);
while(GetMsg(DebPort));
CloseDevice((struct IORequest *)DebReq);
if(DebReq) DeleteIORequest(DebReq);
if(DebPort) DeleteMsgPort(DebPort);
if (DebWin1) CloseWindow(DebWin1);
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}
#else /* No debugging, use intuition only for error messages */
void initintuition(void)
{
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37L);
}
void uninitintuition(void)
{
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}
#endif /* DEBUG */
/*
**
** ReadConfig
**
** Attempt to read in and parse the driver's configuration file.
**
** The files are named by ENV:SANA2/sparX.config where X is the decimal
** representation of the device's unit number.
**
*/
BOOL ReadConfig(struct SPARDevUnit *sdu)
{
UBYTE *linebuff,conffile[40]; /* temporary linebuffer & filename */
STRPTR termchar; /* line terminator */
struct RDArgs *rdargs;
BPTR ConfigFile; /* DOS file desciptor */
LONG args[4]; /* arguments to read from the file */
BOOL status = FALSE;
ULONG linenum=0; /* line counter in config file */
UWORD i;
struct EasyStruct es; /* For errormessage to user */
/* initialize structure for a possible error message */
es.es_StructSize=sizeof(struct EasyStruct);
es.es_Flags=0;
es.es_Title=(char *)SPARName;
es.es_GadgetFormat="Okay";
/* Create the name of our config file.. */
sprintf(conffile,"ENV:SANA2/spar%ld.config",(ULONG)sdu->sdu_UnitNum);
/* ...and open it. */
if(ConfigFile = Open(conffile,MODE_OLDFILE))
{
/* Here, I use ReadArgs() to do the file parsing for me. */
if(linebuff = AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC))
{
if(rdargs = AllocDosObject(DOS_RDARGS, NULL))
{
while(FGets(ConfigFile, linebuff, 255))
{
linenum++;
if(linebuff[0] == '#') /* Skip comment lines */
continue;
rdargs->RDA_Source.CS_Buffer = linebuff;
rdargs->RDA_Source.CS_Length = 256;
rdargs->RDA_Source.CS_CurChr = 0;
rdargs->RDA_DAList = NULL; /* MUST be initalized to NULL */
/* ReadArgs() requires that the line be null-terminated
* or funny things happen. */
termchar = (STRPTR) linebuff + strlen(linebuff);
*termchar = '\n';
termchar++;
*termchar = 0;
for(i = 0; i< 3; i++) args[i]=0; /* clear argument list */
/* Parse the line...*/
/* I use 'DESTADDR' as a string, otherwise I can't check if
* it's omitted. (when using 'DESTADDR/N' and you don't
* fill in this argument in the config.file, args[3] will
* still point to something.)
*/
if(ReadArgs("PARNAME/A,PARUNIT/A/N,PARADDR/A/N,DESTADDR",args,rdargs))
/* if(ReadArgs("PARNAME/A,PARUNIT/A/N,PARADDR/A/N,DESTADDR/N",args,rdargs))
*/
{
strcpy(sdu->sdu_ParDevName,(STRPTR)args[0]);
sdu->sdu_ParUnitNum = *((ULONG *)args[1]);
sdu->sdu_StAddr = sdu->sdu_HwAddr = (UBYTE) *((ULONG *)args[2]);
if(args[3]) sdu->sdu_DestAddr = (UBYTE) atoi((char *)args[3]);
/* if(args[3]) sdu->sdu_DestAddr = (UBYTE) *((ULONG *)args[3]);
*/
else sdu->sdu_DestAddr = (UBYTE) 0;
/* check hardware addresses */
if ((sdu->sdu_HwAddr!=0) && (sdu->sdu_HwAddr!=255) &&
(sdu->sdu_DestAddr!=255))
status = TRUE;
else
{
/* send a notification to the user */
es.es_TextFormat="Invalid hardware address (%d) given.";
EasyRequestArgs(NULL, &es, 0, &sdu->sdu_HwAddr);
}
debug(("Config: Hardware addr:%d, dest.addr:%d\n",(int)sdu->sdu_HwAddr,(int)sdu->sdu_DestAddr))
FreeArgs(rdargs);
break;
}
else /* Argument error */
{
/* Produce an error message in a requester */
es.es_TextFormat="Error in configuration file on line %ld.";
EasyRequestArgs(NULL, &es, 0, &linenum);
break;
}
}
FreeDosObject(DOS_RDARGS,rdargs);
}
FreeMem(linebuff, 256);
}
Close(ConfigFile);
}
return(status);
}
VOID SendPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
{
struct IOParReq *iopar;
struct BufferManagement *bm;
struct Spar_Hdr *PktHdr; /* Spar frame header */
bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
/* Check first if destination hardware address is valid */
if ((ios2->ios2_DstAddr[0]==0) || (ios2->ios2_DstAddr[0]==255))
{
PacketDropped(sdu); /* Can't handle addresses 0 and 255 */
debug(("SendPacket: Bad destination addr:%08lx%04lx (packet dropped).\n",*(LONG *)ios2->ios2_DstAddr,*(UWORD *)(ios2->ios2_DstAddr+4)))
}
else
{
/* Copy the data out of the packet into our temporary buffer. */
if((*bm->bm_CopyFromBuffer)(sdu->sdu_TxBuff+SHDR_LEN,ios2->ios2_Data,ios2->ios2_DataLength))
{
PktHdr=(struct Spar_Hdr *)sdu->sdu_TxBuff; /* Pointer to frame header */
/* Create frame header (Ethernet-like) */
PktHdr->SDstAddr=ios2->ios2_DstAddr[0]; /* Place packet destination Spar address */
/* Place my source address in packet header */
if ((ios2->ios2_SrcAddr[0]==0) || (ios2->ios2_SrcAddr[0]==255)) /* Valid source address ? */
PktHdr->SSrcAddr=sdu->sdu_StAddr; /* Use internal h/w addr. */
else
PktHdr->SSrcAddr=ios2->ios2_SrcAddr[0];
PktHdr->SFrmType=(UWORD)ios2->ios2_PacketType; /* Place frame type */
/* Update statistics, (without header information) */
PacketSent(sdu,ios2->ios2_DataLength);
/* Destination address ok, send it */
iopar = sdu->sdu_ParTx;
iopar->io_Data = sdu->sdu_TxBuff;
iopar->io_Length = ios2->ios2_DataLength+SHDR_LEN; /* include packet header */
iopar->io_Data2 = 0L; /* must be 0 if you do not */
iopar->io_Length2 = 0L; /* use these fields. */
iopar->io_Command = CMD_WRITE;
iopar->io_Error = 0; /* is this needed?? */
iopar->io_Message.mn_Node.ln_Type = 0;
iopar->io_Port = SPAR_PORT;
iopar->io_Addr = (UWORD)ios2->ios2_DstAddr[0];
iopar->io_Flags = PRO_DGRAM;
/* Send the packet to the PARnet device driver */
SendIO((struct IORequest *)iopar);
debug(("SendPacket: Sent packet size %ld addr: %08lx%04lx.\n", ios2->ios2_DataLength, *(LONG *)ios2->ios2_DstAddr,*(UWORD *)(ios2->ios2_DstAddr+4)))
}
else
{
/* Something went wrong...*/
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_BUFF_ERROR;
DoEvent(sdu,S2EVENT_BUFF);
}
}
TermIO(ios2);
}
/*
** This routine is called whenever we think we've got
** a complete packet to satisfy a CMD_READ request.
*/
VOID GotPacket(struct SPARDevUnit *sdu, ULONG length)
{
struct IOSana2Req *ios2;
struct BufferManagement *bm;
ULONG Offset;
struct Spar_Hdr *PktHdr; /* Spar frame header */
if(length)
{
PacketReceived(sdu,length); /* Update statistics */
PktHdr=(struct Spar_Hdr *)sdu->sdu_RxBuff; /* Pointer to frame header */
/* Find an appropriate request wanting this packet type.
* Routine gotten from the agnet.device by ppessi <Pekka.Pessi@hut.fi>
*/
ObtainSemaphore(&sdu->sdu_ListLock);
/* For each queued read request... */
for (ios2 = (struct IOSana2Req *)sdu->sdu_Rx.mlh_Head;
ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
ios2 = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
{
/* Does requested packet type match? */
if (ios2->ios2_PacketType == (ULONG)PktHdr->SFrmType)
{
Remove((struct Node *)ios2); /* Yes, get & remove it from list */
break; /* No more searches needed */
}
}
if(!ios2) /* Nobody wants this packet type? So, it's orphan */
{
ReceivedOrphan(sdu); /* Update statistics */
if (!(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_RxOrph)))
PacketDropped(sdu); /* Nobody is interested in this packet, drop it */
}
ReleaseSemaphore(&sdu->sdu_ListLock);
bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
/* Don't strip frame header when RAW data is requested */
if (ios2->ios2_Req.io_Flags==SANA2IOB_RAW) Offset=0;
else Offset=SHDR_LEN;
/* Copy the data into the protocol stack's buffer using its
* supplied callback routine. */
if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,sdu->sdu_RxBuff+Offset,length-Offset))
{
debug(("GotPack (%d): %08lx%08lx%08lx%08lx\n",length-Offset,*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12)))
/* Copy source and destination addresses */
memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES); /* first clear */
memset(ios2->ios2_SrcAddr, 0, SANA2_MAX_ADDR_BYTES); /* them both. */
ios2->ios2_DstAddr[0]=PktHdr->SDstAddr;
ios2->ios2_SrcAddr[0]=PktHdr->SSrcAddr;
/* Our packetlength (if not SANA2IOB_RAW then strip frame header) */
ios2->ios2_DataLength = length-Offset;
/* Our packet type */
ios2->ios2_PacketType = (ULONG)PktHdr->SFrmType;
#ifdef DEBUG
debug(("GotPacket: Length:%lx ", ios2->ios2_DataLength))
if (ios2->ios2_PacketType==ETHERTYPE_ARP) debug(("Type:ARP "))
else if(ios2->ios2_PacketType==ETHERTYPE_IP) debug(("Type:IP "))
else debug(("Type:%08lx ",ios2->ios2_PacketType))
debug(("Source:%08lx%04lx.\n", *(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4) ))
#endif
}
else
{
ios2->ios2_DataLength = 0;
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_BUFF_ERROR;
DoEvent(sdu,S2EVENT_BUFF);
}
TermIO(ios2);
} /* Length */
}
/*
** This routine initializes our IO requests and buffers for PARnet i/o .
*/
BOOL InitPARnet(struct SPARDevUnit *sdu)
{
ULONG *clr;
BOOL status = FALSE;
/* This is a dirty way of clearing some pointers in the struct SPARDevUnit */
for(clr = (ULONG *) &sdu->sdu_ParRx; clr <= (ULONG *) &sdu->sdu_TxBuff; clr++)
*clr = 0L;
if(sdu->sdu_TxPort = CreateMsgPort()) /* PARnet CMD_WRITE IORequest reply port */
if(sdu->sdu_ParTx = CreateIORequest(sdu->sdu_TxPort,sizeof(struct IOParReq)))
if(sdu->sdu_RxPort = CreateMsgPort()) /* PARnet CMD_READ IORequest reply port */
if(sdu->sdu_ParRx = CreateIORequest(sdu->sdu_RxPort,sizeof(struct IOParReq)))
/* Allocate some buffer memory */
if(sdu->sdu_TxBuff = AllocMem(SPAR_MTU * 2,MEMF_CLEAR|MEMF_PUBLIC))
{
sdu->sdu_RxBuff = sdu->sdu_TxBuff + SPAR_MTU;
status = TRUE; /* flag: initialisation was successful */
}
if(!status)
DeinitPARnet(sdu); /* Something went wrong, release all */
return(status);
}
/*
** This routine cleans up our PARnet i/o requests
** and misc. buffers.
*/
VOID DeinitPARnet(struct SPARDevUnit *sdu)
{
if(sdu->sdu_ParTx)
DeleteIORequest(sdu->sdu_ParTx);
if(sdu->sdu_TxPort)
DeleteMsgPort(sdu->sdu_TxPort);
if(sdu->sdu_ParRx)
DeleteIORequest(sdu->sdu_ParRx);
if(sdu->sdu_RxPort)
DeleteMsgPort(sdu->sdu_RxPort);
if(sdu->sdu_TxBuff)
FreeMem(sdu->sdu_TxBuff,(SPAR_MTU * 2)); /* release both TxBuff & RxBuff */
}
/*
** This routine opens the PARnet device driver and attempts to bring
** the device online.
*/
BOOL OpenPARnet(struct SPARDevUnit *sdu)
{
BOOL status = FALSE;
ULONG odflags = 0;
struct IOParReq *ioTpar,*ioRpar; /* IORequest structures */
/* next variables are used for displaying the error message */
struct EasyStruct es;
ULONG args[2];
ioRpar = sdu->sdu_ParRx;
ioTpar = sdu->sdu_ParTx;
ioRpar->io_Device = NULL;
if (sdu->sdu_TxPort) /* Is this needed?? */
{
ioTpar->io_Message.mn_ReplyPort=sdu->sdu_TxPort;
ioTpar->io_Port = 0;
ioTpar->io_Flags = PRO_CONTROL;
if(!OpenDevice(sdu->sdu_ParDevName,sdu->sdu_ParUnitNum,(struct IORequest *)ioTpar,odflags))
{
/* Set up our PARnet RX parameters */
ioRpar->io_Device = ioTpar->io_Device;
ioRpar->io_Unit = ioTpar->io_Unit;
/* set up IO request for hardware address setting */
ioTpar->io_Command = PPD_SETADDR;
ioTpar->io_Addr = (UWORD)sdu->sdu_StAddr;
if(!DoIO((struct IORequest *)ioTpar)) /* Set my hardware address */
{
/* Close the device again to reset the PRO_CONTROL mode */
CloseDevice((struct IORequest *)ioTpar);
/* Open the device in Data Gram mode */
ioTpar->io_Port = SPAR_PORT;
ioTpar->io_Flags = PRO_DGRAM;
if(!OpenDevice(sdu->sdu_ParDevName,sdu->sdu_ParUnitNum,(struct IORequest *)ioTpar,odflags))
{
/* Assume we're now online */
sdu->sdu_State |= SPARUF_ONLINE;
/* check first if the reply port has already been initalized */
if (sdu->sdu_RxPort) /* Is this really needed?? */
{
/* Queue up the initial CMD_READ command for the PARnet driver. */
ioRpar->io_Message.mn_ReplyPort=sdu->sdu_RxPort;
ioRpar->io_Port = SPAR_PORT; /* PARnet port to listen on */
ioRpar->io_Flags = PRO_DGRAM; /* only DataGram mode supported */
ioRpar->io_Command = CMD_READ;
ioRpar->io_Length = SPAR_MTU;
if (sdu->sdu_RxBuff) /* Is this needed?? */
{
ioRpar->io_Data = sdu->sdu_RxBuff;
SendIO((struct IORequest *)ioRpar);
status = TRUE; /* All ok! */
}
}
}
if(!status)
CloseDevice((struct IORequest *)ioTpar);
}
else /* Can't set PARnet hardware address */
CloseDevice((struct IORequest *)ioTpar);
}
else /* Can't open device */
{
args[0]=(ULONG)sdu->sdu_ParDevName;
args[1]=(ULONG)sdu->sdu_ParUnitNum;
es.es_StructSize=sizeof(struct EasyStruct);
es.es_Flags=0;
es.es_Title="spar.device";
es.es_TextFormat="Couldn't open %s unit %ld.";
es.es_GadgetFormat="Okay";
EasyRequestArgs(NULL, &es, 0, (APTR)args);
}
if(sdu->sdu_State & SPARUF_ONLINE)
MarkTimeOnline(sdu);
}
return(status);
}
/*
** This routine aborts any pending activity with the PARnet
** device driver and then brings the spar driver offline.
*/
VOID ClosePARnet(struct SPARDevUnit *sdu)
{
AbortIO((struct IORequest *)sdu->sdu_ParRx);
WaitIO((struct IORequest *)sdu->sdu_ParRx);
while(GetMsg(sdu->sdu_RxPort));
AbortIO((struct IORequest *)sdu->sdu_ParTx);
WaitIO((struct IORequest *)sdu->sdu_ParTx);
while(GetMsg(sdu->sdu_TxPort));
CloseDevice((struct IORequest *)sdu->sdu_ParRx);
sdu->sdu_State &= ~SPARUF_ONLINE;
}
/*
** This routine is called whenever we need to
** get more data from the PARnet port.
*/
VOID QueueParRequest(struct SPARDevUnit *sdu)
{
sdu->sdu_ParRx->io_Command = CMD_READ;
sdu->sdu_ParRx->io_Data = sdu->sdu_RxBuff;
sdu->sdu_ParRx->io_Length = SPAR_MTU;
SendIO((struct IORequest *)sdu->sdu_ParRx);
}