-- File: GateStats.mesa,  Last Edit: HGM  March 17, 1981  7:27 PM

DIRECTORY
  InlineDefs USING [MesaToBcplLongNumber],
  Process USING [Detach],
  AltoEthernetDefs USING [
    EtherStatsEntry, EtherStatsInfo, ethernetStatsReply, etherVersion],
  GateControlDefs USING [pupStatsAck, pupStatsNak, pupStatsSend],
  PupDefs USING [
    PupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, PupRouterSendThis,
    SwapPupSourceAndDest, ReturnPup, PupSocket, PupSocketMake, veryLongWait],
  DriverDefs USING [Network, GetDeviceChain],
  PupTypes USING [statSoc, fillInPupAddress];

GateStats: PROGRAM
  IMPORTS InlineDefs, Process, PupDefs, DriverDefs
  EXPORTS DriverDefs, GateControlDefs =
  BEGIN OPEN PupDefs;

  soc: PupSocket;

  GateStatsOn: PUBLIC PROCEDURE = BEGIN Process.Detach[FORK Stats[]]; END;

  Stats: PROCEDURE =
    BEGIN
    b: PupBuffer;
    firstNetwork: DriverDefs.Network = DriverDefs.GetDeviceChain[];
    SetupStatsEntries[];
    soc ← PupSocketMake[
      PupTypes.statSoc, PupTypes.fillInPupAddress, veryLongWait];
    DO  -- forever
      IF (b ← soc.get[]) # NIL THEN
	BEGIN
	SELECT b.pupType FROM
	  GateControlDefs.pupStatsSend =>
	    BEGIN
	    target: CARDINAL = b.pupWords[0];
	    network: DriverDefs.Network;
	    IF GetPupContentsBytes[b] # 2 THEN GOTO Ignore;
	    FOR network ← firstNetwork, network.next UNTIL network = NIL DO
	      IF network.netNumber.b # target THEN LOOP;
	      IF network.pupStats = NIL OR network.stats = NIL THEN GOTO Reject;
	      IF network.pupStats[b, network] THEN GOTO Send;
	      GOTO Reject;
	      ENDLOOP;
	    GOTO Reject;
	    END;
	  ENDCASE => GOTO Reject;
	EXITS
	  Send =>
	    BEGIN -- pupLength setup already
	    b.pupType ← GateControlDefs.pupStatsAck;
	    SwapPupSourceAndDest[b];
	    PupRouterSendThis[b];
	    END;
	  Reject => BEGIN ReturnPup[b, GateControlDefs.pupStatsNak, 0]; END;
	  Ignore => BEGIN ReturnFreePupBuffer[b]; END;
	END;
      ENDLOOP;
    END;

  SetupStatsEntries: PUBLIC PROCEDURE =
    BEGIN
    network: DriverDefs.Network;
    FOR network ← DriverDefs.GetDeviceChain[], network.next UNTIL network = NIL DO
      SELECT network.device FROM
	ethernet, ethernetOne => network.pupStats ← EthernetStats;
	ENDCASE;
      ENDLOOP;
    END;

  EthernetStats: PUBLIC PROCEDURE [b: PupBuffer, network: DriverDefs.Network]
    RETURNS [BOOLEAN] =
    BEGIN OPEN AltoEthernetDefs;
    ese: LONG POINTER TO EtherStatsEntry;
    esi: LONG POINTER TO EtherStatsInfo ← network.stats;
    b.pupWords[0] ← ethernetStatsReply;
    ese ← LOOPHOLE[@b.pupWords[1]];
    ese↑ ←
      [version: etherVersion,
	packetsSent: InlineDefs.MesaToBcplLongNumber[esi.packetsSent],
	badSendSatus: InlineDefs.MesaToBcplLongNumber[esi.badSendSatus],
	overruns: InlineDefs.MesaToBcplLongNumber[esi.overruns],
	packetsRecv: InlineDefs.MesaToBcplLongNumber[esi.packetsRecv],
	badRecvStatus: InlineDefs.MesaToBcplLongNumber[esi.badRecvStatus],
	inputOff: InlineDefs.MesaToBcplLongNumber[esi.inputOff], loadTable:];
    FOR i: CARDINAL IN [0..16] DO
      ese.loadTable[i] ← InlineDefs.MesaToBcplLongNumber[esi.loadTable[i]];
      ENDLOOP;
    b.pupLength ← 22 + 2 + 2*SIZE[EtherStatsEntry];
    RETURN[TRUE];
    END;


  GateStatsOn[];
  END.