home *** CD-ROM | disk | FTP | other *** search
- RCS_ID_C="$Id: device.c,v 4.1 1994/02/25 14:55:44 ppessi Exp $";
- /*
- * device.c --- SANA-II test device, device functions
- *
- * Author: ppessi <Pekka.Pessi@hut.fi>
- *
- * Copyright (c) 1993 AmiTCP/IP Group,
- * Helsinki University of Technology, Finland.
- * All rights reserved.
- *
- * Created : Thu Jan 21 17:32:55 1993 ppessi
- * Last modified: Fri Feb 25 01:17:14 1994 ppessi
- *
- * $Log: device.c,v $
- * Revision 4.1 1994/02/25 14:55:44 ppessi
- * Fixed SAS C 6.51 features
- *
- * Revision 2.3 1993/10/20 15:17:52 jraja
- * Added correct prototype for the CheckIO().
- *
- * Revision 2.2 1993/10/14 00:09:43 ppessi
- * Changed RCS Id format
- *
- * Revision 2.1 93/05/14 16:48:21 ppessi
- * Release version
- *
- */
-
- #include <string.h>
-
- #include <dos/dostags.h>
- #include <dos/rdargs.h>
- #include <intuition/intuition.h>
- #include <rexx/storage.h>
- #include <rexx/rxslib.h>
-
- #include <clib/alib_stdio_protos.h>
-
- #ifdef __SASC
- #include <clib/exec_protos.h>
- #include <pragmas/exec_sysbase_pragmas.h>
- #include <clib/dos_protos.h>
- #include <pragmas/dos_pragmas.h>
- #include <clib/utility_protos.h>
- #include <pragmas/utility_pragmas.h>
- #include <clib/timer_protos.h>
- #include <pragmas/timer_pragmas.h>
- #endif
-
- #ifdef __GNUC__
- #include <inline/exec.h>
- #include <inline/dos.h>
- #include <inline/utility.h>
- #include <inline/timer.h>
- #endif
-
- #include "agnet.h"
- #include "agnet_protos.h"
- #include "agnet_rev.h"
- #include "bases.h"
-
- /* Correct prototype for the CheckIO.
- * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits)
- * instead of a pointer (32 bits)!)
- */
- struct IORequest * CheckIO(struct IORequest *req);
-
- /* Local prototypes */
- static ULONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2);
- static VOID CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID ExpungeUnit(struct AgnetDevUnit *adu);
- static VOID TermIO(struct IOSana2Req *ios2);
- static VOID GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type);
- static VOID PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type);
- static VOID PacketOverrun(struct AgnetDevUnit *adu);
- static VOID ReceivedGarbage(struct AgnetDevUnit *adu);
- static VOID PacketDropped(struct AgnetDevUnit *adu, ULONG type);
- static VOID ReceivedOrphan(struct AgnetDevUnit *adu);
- static VOID ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID GetStationAddress(struct AgnetDevUnit *, struct IOSana2Req *);
- static VOID DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID DoEvent(struct AgnetDevUnit *adu, ULONG event);
- static VOID WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
- static VOID SendPacket(struct DelayRequest *delayed);
- static VOID ReceivePacket(struct DelayRequest *delayed);
- static VOID DoReceive(struct AgnetDevUnit *, struct DelayRequest *delayed );
- static VOID CopyBack(struct AgnetDevUnit *, struct IOSana2Req *,
- struct DelayRequest *);
-
- /*
- * Device Open vector
- *
- * a1 - SANA2 IO Request
- * a6 - Pointer to our device base
- * d0 - Unit number
- * d1 - Flags
- */
- ULONG ASM
- DevOpen(REG(a1) struct IOSana2Req *ios2,
- REG(d0) ULONG s2unit,
- REG(d1) ULONG s2flags)
- {
- struct AgnetDevice *AgnetDev = AgnetDeviceBase;
- struct AgnetDevUnit *adu;
- struct TagItem *bufftag;
- struct Library *UtilityBase;
- struct BufferManagement *bm;
- BYTE status = IOERR_UNITBUSY;
-
- /* Make sure our open remains single-threaded.
- We may Wait() when starting up. If somebody
- decides to DoExpunge() before we get the
- semaphore, system is probably blowing up anyways.
- */
- ObtainSemaphore(&AgnetDev->ad_Lock);
-
- /* So we won't expunge ourselves... */
- AgnetDev->ad_Dev_OpenCnt++;
-
- if (s2unit < AD_MAXUNITS) /* Legal Unit */
- if (adu = InitUnit(s2unit)) /* Initialize the unit? */
- if (UtilityBase = OpenLibrary("utility.library", 37L)) { /* For Tag functions */
-
- /* Allocate a structure to store the pointers to the callback routines. */
- if (bm = AllocMem(sizeof(*bm), MEMF_CLEAR|MEMF_PUBLIC)) {
- /* Note: I don't complain if I can't find pointers to the callback routines.
- This is because there are some programs that may need to open me, but
- will never use any device commands that require the callbacks. */
- if (bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
- bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
- }
- if (bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
- bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
- }
- AddTail((struct List *)&adu->adu_BuffMgmt, (struct Node *)bm);
-
- /* Everything went okay. */
- status = 0;
- AgnetDev->ad_Dev_OpenCnt++;
- AgnetDev->ad_Dev_Flags &= ~LIBF_DELEXP;
- adu->adu_Unit_OpenCnt++;
-
- /* Fix up the initial io request */
- ios2->ios2_BufferManagement = (VOID *)bm;
- ios2->ios2_Req.io_Error = 0;
- ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
- ios2->ios2_Req.io_Unit = adu;
- ios2->ios2_Req.io_Device = AgnetDev;
- }
- CloseLibrary(UtilityBase);
- }
-
- /* See if something went wrong. */
- if (status) {
- ios2->ios2_Req.io_Error = status;
- ios2->ios2_Req.io_Unit = (struct Unit *) -1;
- ios2->ios2_Req.io_Device = (struct Device *) -1;
- }
- AgnetDev->ad_Dev_OpenCnt--;
- ReleaseSemaphore(&AgnetDev->ad_Lock);
-
- return status;
- }
-
- /*
- * Device Close vector.
- *
- * a1 - IOReq
- * a6 - Device Pointer
- */
- BPTR ASM
- DevClose(REG(a1) struct IOSana2Req *ios2)
- {
- struct AgnetDevice *AgnetDev = AgnetDeviceBase;
- struct AgnetDevUnit *adu;
- BPTR seglist = 0L;
-
- ObtainSemaphore(&AgnetDev->ad_Lock);
-
- adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
- CloseUnit(adu, ios2);
-
- /* Trash the io_Device and io_Unit fields so that any attempt to use this
- request will die immediatly. */
-
- ios2->ios2_Req.io_Device = (struct Device *) -1;
- ios2->ios2_Req.io_Unit = (struct Unit *) -1;
-
- AgnetDev->ad_Dev_OpenCnt--;
-
- /* Check to see if we've been asked to expunge. */
- if (AgnetDev->ad_Dev_OpenCnt == 0 && AgnetDev->ad_Dev_Flags & LIBF_DELEXP) {
- Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
- }
- ReleaseSemaphore(&AgnetDev->ad_Lock);
-
- return seglist;
- }
-
- /*
- * Device Expunge vector
- *
- * a6 - Device base
- *
- * Note: You may NEVER EVER Wait() in expunge. Period.
- * Don't even *think* about it.
- */
- BPTR ASM
- DevExpunge(VOID)
- {
- struct AgnetDevice *AgnetDev = AgnetDeviceBase;
-
- AgnetDev->ad_Dev_Flags |= LIBF_DELEXP;
- Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
-
- /* We can not expunge */
- return (BPTR)0L;
- }
-
- /*
- * Device Reserved vector (returns 0L)
- */
- ULONG ASM
- DevReserved(VOID)
- {
- return 0L;
- }
-
- /*
- * BeginIO --- dispatch incoming requests
- *
- * a1 - The IO request
- * a6 - The device base
- */
- #define SLIP_IMMEDIATES 0L /* No QUICK IO */
-
- VOID ASM
- DevBeginIO(REG(a1) struct IOSana2Req *ios2)
- {
- register struct AgnetDevice *ad;
- ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
-
- if (ios2->ios2_Req.io_Command < S2_END) {
- if ((ios2->ios2_Req.io_Flags & IOF_QUICK) &&
- ((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)) {
- PerformIO(ios2);
- } else {
- ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
- /* Send this to DEVICE Message Port */
- ad = (struct AgnetDevice*)ios2->ios2_Req.io_Device;
- PutMsg(&ad->ad_MsgPort, (struct Message *)ios2);
- }
- } else {
- ios2->ios2_Req.io_Error = IOERR_NOCMD;
- TermIO(ios2);
- }
- }
-
- /*
- * The device AbortIO() entry point.
- *
- * A1 - The IO request to be aborted.
- * A6 - The device base.
- */
- ULONG ASM
- DevAbortIO(REG(a1) struct IOSana2Req *ios2)
- {
- register struct AgnetDevUnit *adu =
- (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
- register ULONG result = 0L;
-
-
- LockUnit(adu);
- if (ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG) {
- switch(ios2->ios2_Req.io_Command) {
- case CMD_READ: result = AbortReq(&adu->adu_Rx,ios2);
- break;
-
- case CMD_WRITE: result = AbortReq(&adu->adu_Tx,ios2);
- break;
-
- case S2_READORPHAN: result = AbortReq(&adu->adu_RxOrph,ios2);
- break;
-
- case S2_ONEVENT: result = AbortReq(&adu->adu_Events,ios2);
- break;
-
- default: result = IOERR_NOCMD;
- break;
- }
- }
- UnlockUnit(adu);
- return result;
- }
-
- /*
- * This funcion is used to locate an IO request in a linked
- * list and abort it if found.
- */
- static ULONG
- AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
- {
- struct Node *node, *next;
- ULONG result = IOERR_NOCMD;
-
- node = (struct Node *)minlist->mlh_Head;
-
- while (!TAILP(node)) {
- next = node->ln_Succ;
-
- if (node == (struct Node *)ios2) {
- Remove((struct Node *)ios2);
- ios2->ios2_Req.io_Error = IOERR_ABORTED;
- TermIO(ios2);
- result = 0;
- }
- node = next;
- }
- return result;
- }
-
- /*
- * Real expunge
- */
- BOOL
- DoExpunge(struct AgnetDevice *adb)
- {
- ULONG i;
-
- /* Well, if there is somebody trying to open,
- they stuck with this */
- ObtainSemaphore(&adb->ad_Lock);
- if (adb->ad_Device.lib_OpenCnt != 0) {
- ReleaseSemaphore(&adb->ad_Lock);
- return FALSE;
- }
- Forbid();
- Remove((struct Node *)adb);
- Permit();
-
- /* Free up Units */
- for (i=0; i < AD_MAXUNITS; i++) {
- if (adb->ad_Units[i])
- ExpungeUnit((struct AgnetDevUnit *)adb->ad_Units[i]);
- adb->ad_Units[i] = NULL;
- }
-
- return TRUE;
- }
-
- /*
- * InitUnit
- *
- * Initialize (if needed) a new agnet.device Unit
- */
- struct AgnetDevUnit *
- InitUnit(ULONG s2unit)
- {
- struct AgnetDevUnit *adu;
- struct AgnetDevice *adb = AgnetDeviceBase;
-
- /* Check to see if the Unit is already up and running. If
- it is, just drop through. If not, try to start it up. */
- if (adu = (struct AgnetDevUnit *)adb->ad_Units[s2unit])
- return adu;
-
- /* Allocate a new Unit structure */
- adu = AllocMem(sizeof(*adu), MEMF_CLEAR|MEMF_PUBLIC);
- if (!adu)
- return NULL;
-
- /* Do some initialization on the Unit structure */
- #if 0
- NewList(&adu->adu_Unit_MsgPort.mp_MsgList);
- adu->adu_Unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
- adu->adu_Unit_MsgPort.mp_Flags = PA_IGNORE;
- adu->adu_Unit_MsgPort.mp_Node.ln_Name = AGNETDEVNAME;
- #endif
- adu->adu_UnitNum = s2unit;
- adu->adu_Device = (struct Device *) adb;
-
- /* Try to read in our configuration file */
- if (!ReadConfig(adu)) {
- FreeMem(adu, sizeof(*adu));
- return NULL;
- }
-
- /* Initialize our list semaphore */
- InitSemaphore(&adu->adu_Lock);
-
- /* Initialize our linked lists. */
- NewList((struct List *)&adu->adu_FreeToTx);
- NewList((struct List *)&adu->adu_Rx);
- NewList((struct List *)&adu->adu_RxOrph);
- NewList((struct List *)&adu->adu_Tx);
- NewList((struct List *)&adu->adu_Events);
- NewList((struct List *)&adu->adu_Track);
- NewList((struct List *)&adu->adu_BuffMgmt);
-
- /* Allocate memory buffers */
- DoOnline(adu);
-
- /* Set up the Unit structure pointer in the device base */
- adb->ad_Units[s2unit] = adu;
-
- return adu;
- }
-
- /*
- * CloseUnit
- *
- * This function closes unit and frees resources
- * allocated for each opener.
- */
- static VOID
- CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- register struct BufferManagement *bm = ios2->ios2_BufferManagement;
-
- LockUnit(adu);
-
- if (bm) {
- ios2->ios2_BufferManagement = NULL;
- Remove((struct Node *)bm);
- FreeMem(bm, sizeof(*bm));
- }
- adu->adu_Unit.unit_OpenCnt--;
-
- UnlockUnit(adu);
- }
-
- /*
- * ExpungeUnit
- *
- * This function is called from the DoExpunge routine.
- * The unit structure and all subsequent allocations are freed.
- */
- static VOID
- ExpungeUnit(struct AgnetDevUnit *adu)
- {
- struct IOSana2Req *ios2;
- struct SuperS2PTStats *sstats;
- int i;
- struct List *io_queues[5];
-
- /* Eliminate every queues */
- LockUnit(adu);
-
- io_queues[0] = (struct List *)&adu->adu_Rx;
- io_queues[1] = (struct List *)&adu->adu_Tx;
- io_queues[2] = (struct List *)&adu->adu_RxOrph;
- io_queues[3] = (struct List *)&adu->adu_Events;
- io_queues[4] = NULL;
-
- for (i = 0; io_queues[i]; i++) {
- while(ios2 = (struct IOSana2Req *)RemHead(io_queues[i])) {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
- }
-
- /* Tracking data was allocated by us */
- while(sstats = (struct SuperS2PTStats*)
- RemHead((struct List *)&adu->adu_Track)) {
- FreeMem(sstats, sizeof(*sstats));
- }
-
- DoOffline(adu);
-
- UnlockUnit(adu);
-
- FreeMem(adu, sizeof(*adu));
- }
-
- /*
- * This routine is used to dispatch an IO request either from BeginIO
- * or from the Unit process.
- */
- VOID
- PerformIO(struct IOSana2Req *ios2)
- {
- struct AgnetDevUnit *adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
-
- if (ios2->ios2_Req.io_Device ==
- AgnetDeviceBase->ad_Timer.tr_node.io_Device) {
- ReceivePacket(ios2);
- return;
- }
-
- ios2->ios2_Req.io_Error = 0;
-
- switch(ios2->ios2_Req.io_Command) {
- case CMD_READ: ReadPacket(adu,ios2);
- break;
-
- case CMD_WRITE: WritePacket(adu,ios2);
- break;
-
- case S2_DEVICEQUERY: DeviceQuery(adu,ios2);
- break;
-
- case S2_GETSTATIONADDRESS: GetStationAddress(adu,ios2);
- break;
-
- case S2_CONFIGINTERFACE: ConfigInterface(adu,ios2);
- break;
- #if 0
- /* Non-existing commands */
- case S2_ADDSTATIONALIAS:
- case S2_DELSTATIONALIAS:
- #endif
- case S2_ADDMULTICASTADDRESS:
- case S2_DELMULTICASTADDRESS:
- case S2_MULTICAST:
- ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2);
- break;
-
- case S2_BROADCAST: WritePacket(adu,ios2);
- break;
-
- case S2_TRACKTYPE: TrackType(adu,ios2);
- break;
-
- case S2_UNTRACKTYPE: UnTrackType(adu,ios2);
- break;
-
- case S2_GETTYPESTATS: GetTypeStats(adu,ios2);
- break;
-
- case S2_GETSPECIALSTATS: GetSpecialStats(adu,ios2);
- break;
-
- case S2_GETGLOBALSTATS: GetGlobalStats(adu,ios2);
- break;
-
- case S2_ONEVENT: OnEvent(adu,ios2);
- break;
-
- case S2_READORPHAN: ReadOrphan(adu,ios2);
- break;
-
- case S2_ONLINE: Online(adu,ios2);
- break;
-
- case S2_OFFLINE: Offline(adu,ios2);
- break;
-
- default:
- ios2->ios2_Req.io_Error = IOERR_NOCMD;
- TermIO(ios2);
- break;
- }
- }
-
- /*
- * This function is used to return an IO request
- * back to the sender.
- */
- static VOID
- TermIO(struct IOSana2Req *ios2)
- {
- if (!(ios2->ios2_Req.io_Flags & IOF_QUICK))
- ReplyMsg((struct Message *)ios2);
- }
-
- /*
- * This function returns any device specific statistics that
- * we may have.
- *
- * Currently, there is none.
- *
- * Ethernet may require some
- */
- static VOID
- GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct Sana2SpecialStatHeader *stats;
-
- stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
-
- stats->RecordCountSupplied = 0;
- TermIO(ios2);
- }
-
- /*
- * This function returns the global statistics for the
- * slip device.
- */
- static VOID
- GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct Sana2DeviceStats *stats;
-
- if (stats = (struct Sana2DeviceStats *)ios2->ios2_StatData) {
- stats->PacketsReceived = adu->adu_Stats.PacketsReceived;
- stats->PacketsSent = adu->adu_Stats.PacketsSent;
- stats->BadData = adu->adu_Stats.BadData;
- stats->Overruns = adu->adu_Stats.Overruns;
- stats->UnknownTypesReceived = adu->adu_Stats.UnknownTypesReceived;
- stats->Reconfigurations = adu->adu_Stats.Reconfigurations;
- stats->LastStart.tv_secs = adu->adu_Stats.LastStart.tv_secs;
- stats->LastStart.tv_micro = adu->adu_Stats.LastStart.tv_secs;
- } else {
- ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
- ios2->ios2_WireError = S2WERR_NULL_POINTER;
- }
- TermIO(ios2);
- }
-
- /*
- * This function returns statistics for a specific
- * type of packet that is being tracked.
- *
- * Just to be thourough, I have arbitrarily picked
- * the packet type for SLIP IP packets to be 2048, the
- * same as that used for Ethernet. This will at least
- * allow you to track IP packets.
- */
- static VOID
- GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct Sana2PacketTypeStats *stats;
- struct SuperS2PTStats *sstats;
-
- if (stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData) {
- LockUnit(adu);
-
- sstats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- /* Find asked packet type from tracking list */
- while (sstats->ss_Node.mln_Succ) {
- if (ios2->ios2_PacketType == sstats->ss_PType) {
- stats->PacketsSent = sstats->ss_Stats.PacketsSent;
- stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
- stats->BytesSent = sstats->ss_Stats.BytesSent;
- stats->BytesReceived = sstats->ss_Stats.BytesReceived;
- stats->PacketsDropped = sstats->ss_Stats.PacketsDropped;
- break;
- }
- sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
- }
- UnlockUnit(adu);
- if (!sstats->ss_Node.mln_Succ) {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- } else {
- ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
- ios2->ios2_WireError = S2WERR_NULL_POINTER;
- }
- TermIO(ios2);
- }
-
- /*
- * This function adds a packet type to the list
- * of those that are being tracked.
- */
- static VOID
- TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct SuperS2PTStats *stats;
- ULONG type = ios2->ios2_PacketType;
-
- LockUnit(adu);
-
- stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- while (stats->ss_Node.mln_Succ) {
- if (type == stats->ss_PType) {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- if (!stats->ss_Node.mln_Succ) {
- if(stats = AllocMem(sizeof(*stats), MEMF_CLEAR|MEMF_PUBLIC)) {
- stats->ss_PType = type;
- AddTail((struct List *)&adu->adu_Track, (struct Node *)stats);
- }
- }
- UnlockUnit(adu);
-
- TermIO(ios2);
- }
-
- /*
- * This function removes a packet type from the
- * list of those that are being tracked.
- */
- static VOID
- UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct SuperS2PTStats *stats;
-
- LockUnit(adu);
-
- stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- while (stats->ss_Node.mln_Succ) {
- if (ios2->ios2_PacketType == stats->ss_PType) {
- Remove((struct Node *)stats);
- FreeMem(stats, sizeof(*stats));
- stats = NULL;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- if(stats) {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- UnlockUnit(adu);
-
- TermIO(ios2);
- }
-
- /*
- * This function is called whenever a packet is received
- */
- static VOID
- PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type)
- {
- struct SuperS2PTStats *stats;
-
- adu->adu_Stats.PacketsReceived++;
-
- LockUnit(adu);
-
- stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- while (stats->ss_Node.mln_Succ) {
- if (stats -> ss_PType == type) {
- stats -> ss_Stats.PacketsReceived++;
- stats -> ss_Stats.BytesReceived += length;
- break;
- }
- stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
- }
-
- UnlockUnit(adu);
- }
-
- /*
- * This function is called whenever a packet is sent
- */
- static VOID
- PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type)
- {
- struct SuperS2PTStats *stats;
-
- adu->adu_Stats.PacketsSent++;
-
- LockUnit(adu);
-
- stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- while (stats->ss_Node.mln_Succ) {
- if (stats -> ss_PType == type) {
- stats -> ss_Stats.PacketsSent++;
- stats -> ss_Stats.BytesSent += length;
- break;
- }
- stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
- }
-
- UnlockUnit(adu);
- }
-
- /*
- * This function is called a packet overruns
- */
- static VOID
- PacketOverrun(struct AgnetDevUnit *adu)
- {
- adu->adu_Stats.Overruns++;
- DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
- }
-
- /*
- * This function is called whenever a packet with
- * garbage data is encountered.
- */
- static VOID
- ReceivedGarbage(struct AgnetDevUnit *adu)
- {
- adu->adu_Stats.BadData++;
- DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
- }
-
- /*
- * This function is called whenever a packet
- * is dropped by the SLIP driver.
- */
- static VOID
- PacketDropped(struct AgnetDevUnit *adu, ULONG type)
- {
- struct SuperS2PTStats *stats;
-
- LockUnit(adu);
-
- stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
-
- while (stats->ss_Node.mln_Succ) {
- if (stats -> ss_PType == type) {
- stats -> ss_Stats.PacketsDropped++;
- break;
- }
- stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
- }
-
- UnlockUnit(adu);
- }
-
- /*
- * This function is called whenever an orphan packet
- * is received
- */
- static VOID
- ReceivedOrphan(struct AgnetDevUnit *adu)
- {
- adu->adu_Stats.UnknownTypesReceived++;
- }
-
- /*
- * This function handles S2_CONFIGINTERFACE commands.
- */
- static VOID
- ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- /* Note: we may only be configured once. */
- if (!(adu->adu_State & AGUF_CONFIG)) {
- switch (adu->adu_HardwareType) {
- case S2WireType_PPP:
- case S2WireType_SLIP:
- case S2WireType_CSLIP:
- case S2WireType_Ethernet:
- case S2WireType_IEEE802:
- case S2WireType_Arcnet:
- case S2WireType_LocalTalk:
- case S2WireType_AmokNet:
- /* Copy given address as our Station Address */
- memcpy(&adu->adu_Addr, &ios2->ios2_SrcAddr, MAX_ADDR_BYTES);
- /*FALLTHROUGH*/
- default:
- adu->adu_State |= AGUF_CONFIG;
- }
- } else {
- /* Sorry, we're already configured. */
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
- }
- TermIO(ios2);
- }
-
- /*
- * This function handles S2_GETSTATIONADDRESS commands.
- */
- static VOID
- GetStationAddress(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- memcpy(ios2->ios2_DstAddr, adu->adu_Addr, MAX_ADDR_BYTES);
- if (adu->adu_State & AGUF_CONFIG)
- memcpy(ios2->ios2_SrcAddr, adu->adu_Addr, MAX_ADDR_BYTES);
- else
- memset(ios2->ios2_SrcAddr, 0xff, MAX_ADDR_BYTES);
- TermIO(ios2);
- }
-
- /*
- * This function handles S2_DEVICEQUERY comands.
- */
- static VOID
- DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct Sana2DeviceQuery *sdq;
-
- sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
-
- sdq->DeviceLevel = 0L;
- sdq->AddrFieldSize = adu->adu_AddrFieldSize;
- sdq->MTU = adu->adu_MaxTU;
- sdq->BPS = adu->adu_BPS;
- sdq->HardwareType = adu->adu_HardwareType;
-
- sdq->SizeSupplied = sizeof(*sdq);
- TermIO(ios2);
- }
-
- /*
- * This routime handles CMD_ONLINE commands.
- */
- static VOID
- Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- if (!(adu->adu_State & AGUF_ONLINE)) {
- /* We're offline. Go online. */
- LockUnit(adu);
- if (DoOnline(adu)) {
- /* Couldn't get online */
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- UnlockUnit(adu);
- }
- TermIO(ios2);
- }
-
- /*
- * Actual Online, return 0 on success
- *
- * Caller should have a lock on the unit
- */
- LONG
- DoOnline(struct AgnetDevUnit *adu)
- {
- struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
- ULONG mtu; LONG i; BOOL error = TRUE;
- struct DelayRequest *txed;
-
- /* Allocate transfer buffer */
- mtu = adu->adu_MaxTU + 64;
- for (i = 0; i < MAX_TXED; i++) {
- if (adu->adu_TxEd[i]) {
- error = FALSE;
- continue;
- }
- if (!(txed = CreateIORequest(&adb->ad_MsgPort,
- sizeof(struct DelayRequest) + mtu)))
- break;
- error = FALSE;
- adu->adu_TxEd[i] = txed;
- txed->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
- txed->tr_node.io_Device = adb->ad_Timer.tr_node.io_Device;
- txed->tr_node.io_Unit = adb->ad_Timer.tr_node.io_Unit;
- txed->tr_node.io_Command = TR_ADDREQUEST;
- txed->dr_Unit = adu;
- txed->dr_Len = mtu;
- AddHead(&adu->adu_FreeToTx, txed);
- }
-
- if (!error) {
- adu->adu_State |= AGUF_ONLINE;
- GetSysTime(&adu->adu_Stats.LastStart);
- /* In case someone wants to know...*/
- DoEvent(adu, S2EVENT_ONLINE);
- }
- return error;
- }
-
- /*
- * This routine handles CMD_OFFLINE commands.
- * Any pending read or write request will be sent to
- * their owners
- */
- static VOID
- Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
-
- if (adu->adu_State & AGUF_ONLINE) {
- /* We're online, so shut everything down. */
- LockUnit(adu);
- DoOffline(adu);
- UnlockUnit(adu);
- }
-
- TermIO(ios2);
- }
-
- /*
- * Put the unit offline
- *
- * Caller should have a lock on the unit
- */
- VOID
- DoOffline(struct AgnetDevUnit *adu)
- {
- struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
- struct IOSana2Req *ios2;
- int i;
- struct DelayRequest *txed;
-
- adu->adu_State &= ~AGUF_ONLINE;
-
- while(ios2 = (struct IOSana2Req *)
- RemHead((struct List *)&adu->adu_Rx)) {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- while(ios2 = (struct IOSana2Req *)
- RemHead((struct List *)&adu->adu_RxOrph)) {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- while(ios2 = (struct IOSana2Req *)
- RemHead((struct List *)&adu->adu_Tx)) {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- /*
- * Abort still pending delayrequests,
- * free all delayrequests
- */
- for (i = MAX_TXED - 1; i >= 0; i--) {
- if (txed = adu->adu_TxEd[i]) {
- if (!CheckIO(txed))
- AbortIO(txed);
- WaitIO(txed); /* also removes from free queue */
- DeleteIORequest(txed);
- }
- adu->adu_TxEd[i] = NULL;
- }
-
- DoEvent(adu, S2EVENT_OFFLINE);
- }
- /*
- * This routine handles S2_ONEVENT commands
- */
- static VOID
- OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- /* Two special cases.
- * If we are (on/off)line, and ask (on/off)line event,
- * we return immediately
- */
- if (ios2->ios2_WireError == S2EVENT_ONLINE &&
- adu->adu_State & AGUF_ONLINE ||
- ios2->ios2_WireError == S2EVENT_OFFLINE &&
- !(adu->adu_State & AGUF_ONLINE)) {
- TermIO(ios2);
- } else {
- LockUnit(adu);
- AddTail((struct List *)&adu->adu_Events, (struct Node *)ios2);
- UnlockUnit(adu);
- }
- }
-
- /*
- * This routine is called whenever an "important"
- * SANA-II event occurs.
- */
- static VOID
- DoEvent(struct AgnetDevUnit *adu, ULONG event)
- {
- struct IOSana2Req *ios2;
- struct IOSana2Req *ios2_next;
-
- LockUnit(adu);
-
- ios2 = (struct IOSana2Req *)adu->adu_Events.mlh_Head;
-
- while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ) {
- ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
-
- /* Is this the event they are looking for? */
- if(ios2->ios2_WireError & event) {
- Remove((struct Node *)ios2);
- ios2->ios2_WireError = event;
- TermIO(ios2);
- }
- ios2 = ios2_next;
- }
-
- UnlockUnit(adu);
- }
-
- /*
- * This function is used for handling CMD_WRITE and S2_BROADCAST
- * commands.
- */
- static VOID
- WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- /* Make sure that we are online. */
- if (!(adu->adu_State & AGUF_ONLINE)) {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- return;
- }
-
- /* Is the data length legal? */
- if (ios2->ios2_DataLength < adu->adu_MinTU ||
- ios2->ios2_DataLength > adu->adu_MaxTU) {
- /* Sorry, the packet is too long or too small! */
- ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2);
- DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_ERROR);
- return;
- }
-
- /* We call the SendPacket if no delay */
- ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
-
- {
- struct DelayRequest *delayed;
- LockUnit(adu);
- AddTail((struct List *)&adu->adu_Tx,(struct Node *)ios2);
- /*
- * If there is free delay requests,
- * try to send immediately
- */
- delayed = (struct DelayRequest *)
- RemHead((struct List *)&adu->adu_FreeToTx);
- UnlockUnit(adu);
-
- if (delayed)
- SendPacket(delayed);
- }
- return;
- }
-
- /*
- * This routine handles CMD_READ commands. We
- * always queue these unless we're offline.
- */
- static VOID
- ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- if(adu->adu_State & AGUF_ONLINE) {
- /* Queue it... */
- LockUnit(adu);
- AddTail((struct List *)&adu->adu_Rx, (struct Node *)ios2);
- UnlockUnit(adu);
- return;
- }
-
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- /*
- * This routine handles CMD_READORPHAN commands. We
- * always queue these unless we're offline.
- */
- static VOID
- ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
- {
- if(adu->adu_State & AGUF_ONLINE) {
- /* Queue it... */
- LockUnit(adu);
- AddTail((struct List *)&adu->adu_RxOrph, (struct Node *)ios2);
- UnlockUnit(adu);
- return;
- }
-
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- /*
- * "Send" next queued packet
- */
- static VOID
- SendPacket(struct DelayRequest *delayed)
- {
- struct AgnetDevUnit *adu = delayed->dr_Unit;
- struct BufferManagement *bm;
- struct IOSana2Req *ios2 = NULL;
- LONG length; ULONG delay;
-
- LockUnit(adu);
-
- while (!ios2) {
- ios2 = (struct IOSana2Req *)RemHead((struct List *)&adu->adu_Tx);
- /* There is nothing to send */
- if (!ios2) {
- AddHead((struct List *)&adu->adu_FreeToTx,(struct Node *)delayed);
- UnlockUnit(adu);
- return;
- }
-
- length = ios2->ios2_DataLength;
-
- /* Update statistics */
- PacketSent(adu, length, ios2->ios2_PacketType);
-
- /* Should we lose the packet? */
- if (adu->adu_Loss && adu->adu_Loss > LRandom() % LOSS_MAX) {
- TermIO(ios2);
- ios2 = NULL;
- }
- }
- UnlockUnit(adu);
-
- if (length > delayed->dr_Len)
- length = delayed->dr_Len;
-
- bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
-
- /* Copy the data out of the packet into timer request buffer. */
- if (bm->bm_CopyFromBuffer &&
- (*bm->bm_CopyFromBuffer) /* we should have this tag, really */
- (delayed->dr_Data, ios2->ios2_Data, length)) {
- delayed->dr_DataLen = length;
- /* Copy addresses */
- if ((delayed->dr_PPUnit = adu->adu_PPUnit) < 0) {
- WORD adrlen = adu->adu_AddrFieldSize + 7 >> 3;
- memcpy(delayed->dr_DstAddr, ios2->ios2_DstAddr, adrlen);
- memcpy(delayed->dr_SrcAddr, adu->adu_Addr, adrlen);
- }
- /* Set hwtype */
- delayed->dr_HardwareType = adu->adu_HardwareType;
- delayed->dr_PacketType = ios2->ios2_PacketType;
- /* We should recognize broadcasts or multicasts */
- delayed->dr_Cmd = ios2->ios2_Req.io_Command;
- /* Make errors */
- if (adu->adu_Errors) {
- LONG total = adu->adu_Errors * length * 8 / (LRandom() % ERRORS_MAX);
- while (total-- > 0) {
- /* Make a bit error.. */
- ULONG position = LRandom() & 0x7fffffffL;
- /* flip a bit */
- delayed->dr_Data[(position / 8) % length] ^= 1 << (position % 8);
- }
- }
-
- /* calculate delay */
- delay = adu->adu_Delay;
- if (delay && adu->adu_Deviation)
- delay = RandomDev(delay, adu->adu_Deviation);
-
- if (delay) {
- delayed->tr_node.io_Command = TR_ADDREQUEST;
- delayed->tr_time.tv_secs = delay / 1000;
- delayed->tr_time.tv_micro = (delay % 1000) * 1000;
- SendIO(delayed);
- } else {
- /* Fallthrough */
- ReceivePacket(delayed);
- }
- } else {
- /* Something went wrong...*/
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_BUFF | S2EVENT_ERROR);
- }
-
- TermIO(ios2);
- }
-
- /*
- * This routine is called whenever a packet is received.
- * It return all appropriate read requests
- */
- static VOID
- ReceivePacket(struct DelayRequest *delayed)
- {
- struct AgnetDevUnit *adu;
- int i;
-
- if (delayed->dr_PPUnit >= 0 && delayed->dr_PPUnit < AD_MAXUNITS) {
- adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[delayed->dr_PPUnit];
- if (adu)
- DoReceive(adu, delayed);
- } else {
- for (i = 0; i < AD_MAXUNITS; i++) {
- if (!(adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[i]))
- continue; /* No unit */
- if (delayed->dr_HardwareType != adu->adu_HardwareType)
- continue; /* Different hardware */
- if (delayed->dr_Cmd != S2_BROADCAST &&
- memcmp(delayed->dr_DstAddr, adu->adu_Addr,
- adu->adu_AddrFieldSize + 7 >> 3))
- continue; /* Address mismatched */
- DoReceive(adu, delayed);
- }
- }
-
- SendPacket(delayed);
- }
-
- /*
- * DoReceive
- */
- static VOID
- DoReceive(struct AgnetDevUnit *adu, struct DelayRequest *delayed)
- {
- ULONG length = delayed->dr_DataLen;
- ULONG type = delayed->dr_PacketType;
- struct IOSana2Req *rxr;
-
- /* Update statistics */
- PacketReceived(adu, length, type);
- if (adu->adu_MaxTU < length) {
- PacketOverrun(adu);
- return;
- }
- if (adu->adu_MinTU > length) {
- ReceivedGarbage(adu);
- return;
- }
-
- /* Find an appropriate request wanting this packet type */
- LockUnit(adu);
-
- for (rxr = (struct IOSana2Req *)adu->adu_Rx.mlh_Head;
- rxr->ios2_Req.io_Message.mn_Node.ln_Succ;
- rxr = (struct IOSana2Req *)rxr->ios2_Req.io_Message.mn_Node.ln_Succ) {
- if (rxr->ios2_PacketType == type) {
- Remove((struct Node *)rxr);
- CopyBack(adu, rxr, delayed);
- rxr = NULL;
- break;
- }
- }
-
- if (rxr) {
- /* Nobody wants this packet type? So, it's orphan */
- ReceivedOrphan(adu);
- if (rxr = (struct IOSana2Req *)
- RemHead((struct List *)&adu->adu_RxOrph)) {
- rxr -> ios2_PacketType = type;
- CopyBack(adu, rxr, delayed);
- } else {
- /* Nobody is interested in this packet, drop it */
- PacketDropped(adu, type);
- }
- }
-
- UnlockUnit(adu);
- }
-
- /*
- * Copy received packet into a request,
- * return the request to the caller
- */
- static VOID
- CopyBack(struct AgnetDevUnit *adu, struct IOSana2Req *ios2,
- struct DelayRequest *delayed)
- {
- struct BufferManagement * bm =
- (struct BufferManagement *)ios2->ios2_BufferManagement;
- void *data = delayed->dr_Data;
- ULONG length = delayed->dr_DataLen;
- WORD adrlen = (adu->adu_AddrFieldSize + 7) >> 3;
-
- /* Copy the data into the protocol stack's buffer using its
- supplied callback routine. */
- if (bm->bm_CopyToBuffer &&
- (*bm->bm_CopyToBuffer)(ios2->ios2_Data, data, length)) {
- ios2->ios2_DataLength = length;
-
- if (delayed->dr_Cmd == S2_BROADCAST) {
- ios2->ios2_Req.io_Flags |= SANA2IOB_BCAST;
- memset(ios2->ios2_DstAddr, 0xff, adrlen);
- } else {
- memcpy(ios2->ios2_DstAddr, adu->adu_Addr, adrlen);
- }
- memcpy(ios2->ios2_SrcAddr, delayed->dr_SrcAddr, adrlen);
-
- TermIO(ios2);
- return;
- } else {
- ios2->ios2_DataLength = 0;
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_RX | S2EVENT_BUFF | S2EVENT_ERROR);
- TermIO(ios2);
- return;
- }
- }
-
-
-