-- File: SptpImpl.mesa - last edit:
-- AOF 3-Feb-88 11:26:40
-- Copyright (C) 1987, 1988 by Xerox Corporation. All rights reserved.
DIRECTORY
Buffer USING [Buffer, Byte, Dequeue, Device],
CommFlags USING [doStats, driverStats],
CommHeap USING [zone],
CommunicationInternal USING [NSPackageDestroy, NSPackageMake],
Driver USING [Device, GetInputBuffer, ReturnFreeBuffer],
Environment USING [Byte, bytesPerWord],
Inline USING [HighByte, LongCOPY, LowByte],
Mopcodes USING [zADD, zAND, zLI1, zLINB],
NetworkStreamImpl USING [xmtr, rcvr, rexmtr],
NSBuffer USING [Body],
NSTypes USING [bytesPerIDPHeader],
PhoneAdoption USING [],
PhoneNet USING [EntityClass, Negotiation],
Protocol1 USING [
AddFamilyMember, DecapsulatorProc, EncapsulatorProc, Family,
GetContext, GetFamilyUnit, MatrixRecord, RemoveFamilyMember],
RoutingTable USING [ContextObject, NetworkContext],
RS232C USING [ChannelHandle, CommParamHandle],
SptpOps USING [
CreateDriver, defaultMaxRS232CBytes, GetDevice, GetEntityClass,
GetVersion, maxRS232CBytes, minRS232CBytes, point5Duplex,
ReservationObject, siuSupport, StatsRecord],
SptpProtocol USING [
Control, ControlBody, Encapsulation, EncapsulationFromBlock,
EncapsulationObject, EntityClass, MasterSlaveRelationship,
PacketType, Protocol, ProtocolProc, ProtocolVersion],
SptpStats USING [Incr],
SppOps USING [SetSppSpy, SppSpyProc],
System USING [
GetClockPulses, GetGreenwichMeanTime, HostNumber, MicrosecondsToPulses,
nullHostNumber, nullNetworkNumber];
SptpImpl: MONITOR LOCKS protocol.lock↑ USING protocol: SptpProtocol.Protocol
IMPORTS
Buffer, CommunicationInternal, CommHeap, Driver, Inline, Protocol1,
SptpOps, SptpProtocol, SptpStats, SppOps, System
EXPORTS Buffer, PhoneAdoption, PhoneNet, SptpProtocol =
BEGIN
--This doesn't support 1/2 duplex even though the interface says it does
point5Duplex: BOOLEAN = ~SptpOps.point5Duplex;
bpw: NATURAL = Environment.bytesPerWord;
Device: PUBLIC <<Buffer>> TYPE = Driver.Device;
Unsupported: PUBLIC <<PhoneNet>> ERROR = CODE;
IllegalEntityClass: PUBLIC <<PhoneNet>> ERROR = CODE;
StatsPointer: TYPE = LONG POINTER TO SptpOps.StatsRecord;
InvalidLineNumber: PUBLIC <<PhoneNet, PhoneAdoption>> ERROR = CODE;
pvVersionLow: SptpProtocol.ProtocolVersion = version3; --really low
pvVersionHigh: SptpProtocol.ProtocolVersion = version4; --includes 'more' bit
TwoBytes: TYPE = RECORD[hi, lo: Environment.Byte];
Forty8Bitter: TYPE = MACHINE DEPENDENT RECORD[one, two, three: WORD];
clock: RECORD[to1, to2, to3, to4, to5, to6: LONG CARDINAL]; --pulses
<<
The following variable assumes that we are connected via a single local
rs232c port. Watch out for multi ports, etc.
>>
AdoptForNS: PUBLIC <<PhoneAdoption>> PROC[lineNumber: CARDINAL] =
BEGIN
family: Protocol1.Family;
matrix: Protocol1.MatrixRecord;
device: Device = SptpOps.GetDevice[lineNumber];
IF device = NIL THEN ERROR InvalidLineNumber;
family ← CommunicationInternal.NSPackageMake[];
matrix ← [
family: family, context: ,
encapsulator: NsEncapsulation, decapsulator: NsDecapsulation];
matrix.context ← CommHeap.zone.NEW[RoutingTable.ContextObject ← [
netNumber: System.nullNetworkNumber, network: device, stats: NIL]];
Protocol1.AddFamilyMember[device, @matrix];
IF CommFlags.doStats THEN SptpStats.Incr[adoptNS];
END; --AdoptForNS
DisownFromNS: PUBLIC <<PhoneAdoption>> PROC [lineNumber: CARDINAL] =
BEGIN
family: Protocol1.Family;
context: RoutingTable.NetworkContext;
device: Device = SptpOps.GetDevice[lineNumber];
IF device = NIL THEN ERROR InvalidLineNumber;
context ← Protocol1.GetContext[device, ns];
family ← Protocol1.GetFamilyUnit[ns];
Protocol1.RemoveFamilyMember[device, family];
CommHeap.zone.FREE[@context];
CommunicationInternal.NSPackageDestroy[];
IF CommFlags.doStats THEN SptpStats.Incr[disownNS];
END; --DisownFromNS
Initialize: PUBLIC <<PhoneNet>> PROC[
lineNumber: CARDINAL, channel: RS232C.ChannelHandle,
commParams: RS232C.CommParamHandle, negotiationMode: PhoneNet.Negotiation,
hardwareStatsAvailable: BOOLEAN, clientData: LONG UNSPECIFIED ← 0,
ourEntityClass: PhoneNet.EntityClass,
clientHostNumber: System.HostNumber ← System.nullHostNumber] =
-- REPORTS IllegalEntityClass, Unsupported
BEGIN
reservation: SptpOps.ReservationObject ← [
lineSpeed: commParams.lineSpeed, duplex: commParams.duplex,
lineNumber: lineNumber, entity: ourEntityClass];
--IF lineNumber # 0 THEN ERROR Unsupported;
IF ~point5Duplex AND (reservation.duplex = half) THEN ERROR Unsupported;
IF ourEntityClass = siu THEN ERROR IllegalEntityClass;
SptpOps.CreateDriver[@reservation];
IF CommFlags.doStats THEN SptpStats.Incr[createDriver];
END; --Initialize
Destroy: PUBLIC <<PhoneNet>> PROC[lineNumber: CARDINAL] =
BEGIN
device: Driver.Device = SptpOps.GetDevice[lineNumber];
IF device = NIL THEN RETURN WITH ERROR InvalidLineNumber;
device.deleteDriver[]; --else delete the driver
END; --Destroy
--**************** Encapsulation and decapsulation **************
NsDecapsulation: PUBLIC Protocol1.DecapsulatorProc =
--PROCEDURE [b: Buffer.Buffer] RETURNS [type: Buffer.Type]
BEGIN
<<
When coming in here we are assured that b.linkLayer.blockPointer
points to the beginning of the physical frame. That frame starts with
the sptp's encapsulation record. From that information we should be
able to compute the address of the data portion.
These calls to SptpOps.Get* are expensive. It would be nice to be able
to get to some state object more cheaply to determine whether we are
connected to an SIU or not.
>>
size: NATURAL;
body: NSBuffer.Body;
device: Device = b.fo.network; --get pointer to network
version: SptpProtocol.ProtocolVersion = SptpOps.GetVersion[device];
WITH e: LOOPHOLE[b.linkLayer.blockPointer, SptpProtocol.Encapsulation]
SELECT FROM
ns => size ←
IF version > version2 THEN SIZE[ns SptpProtocol.EncapsulationObject]
ELSE SIZE[siuSet SptpProtocol.EncapsulationObject];
siuSet, siuEcho, siuDetermineLS => RETURN[orphan]; --gun these down
<<
SIU knows nothing but ns, so that's as good as packet type.
The SIU doesn't always set the packet type to be ns.
We'll **assume** that the packet is an ns packet, and count on the
level 1 checksums to help us out.
>>
ENDCASE => --special test for SIUs
IF SptpOps.GetEntityClass[device] # siu THEN RETURN[vagrant] --go away
ELSE size ← SIZE[siuSet SptpProtocol.EncapsulationObject]; --see above
body ← LOOPHOLE[b.linkLayer.blockPointer + size]; --that's fair
b.highLayer ← [LOOPHOLE[body], 0, body.pktLength]; --from the packet
b.linkLayer.stopIndexPlusOne ← size ← (bpw * size); --'size' now bytes
SELECT TRUE FROM
(b.fo.driver.length < NSTypes.bytesPerIDPHeader) =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[decapOrphan];
RETURN[orphan]; --busted
END;
(body.pktLength < NSTypes.bytesPerIDPHeader) =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[decapOrphan];
RETURN[orphan]; --busted
END;
ENDCASE =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[decapNS];
RETURN[ns]; --busted
END;
END; --NsDecapsulation
NsEncapsulation: PUBLIC Protocol1.EncapsulatorProc =
BEGIN
<<
Coming in here we know that the packet is an NS packet and that
b.highLayer.blockPointer points to the NSBuffer.BodyBody. We need to back
off some number of bytes from that point and stick in the proper encap-
sulation.
NB: The Inline.LongCOPYs are here because the compiler generates somewhat
unuseful code if you use a more direct approach to things. It first blaps
in a non-descriminated record which is several bytes longer than an
ns SptpProtocol.EncapsulationObject. Then it goes back and fills in the
particulars. Regettably by then the first 'n' bytes of the original
packet are destroyed.
>>
size: NATURAL; --this variable is overloaded
link: LONG POINTER; --computed to point to data link fields
encapsulation: SptpProtocol.EncapsulationObject; --this is our local copy
device: Device = b.fo.network; --get pointer to network
body: NSBuffer.Body = LOOPHOLE[b.highLayer.blockPointer];
of: NATURAL = body.pktLength / SptpOps.defaultMaxRS232CBytes;
version: SptpProtocol.ProtocolVersion = SptpOps.GetVersion[device];
SELECT version FROM
version4 =>
BEGIN
encapsulation ← [ns[LTA: FALSE, more: (of # 0), fragment: [0, of]]];
size ← SIZE[ns SptpProtocol.EncapsulationObject];
END;
version3 =>
BEGIN
IF (of # 0) THEN ERROR Unsupported;
encapsulation ← [ns[LTA: FALSE, more: FALSE, fragment: [0, 0]]];
size ← SIZE[ns SptpProtocol.EncapsulationObject];
END;
version2 =>
BEGIN
encapsulation ← [siuSet[LTA: FALSE, reserved: 0,
immedDest: NARROW[immediate, LONG POINTER TO System.HostNumber]↑]];
SmashPacketType[@encapsulation, ns]; --looks bad, feels worse!
size ← SIZE[siuSet SptpProtocol.EncapsulationObject];
END;
ENDCASE => ERROR Unsupported;
link ← body - size; --this is backoff to beginning of link layer
Inline.LongCOPY[to: link, from: @encapsulation, nwords: size];
size ← bpw * size; -- now represents data link size in bytes
b.linkLayer ← [link, 0, size]; --set the link layer values
b.fo.driver.length ← Roundup[body.pktLength] + size; --frame is sum of both
IF CommFlags.doStats THEN SptpStats.Incr[encapNS];
END; --NsEncapsulation
Roundup: PROC[NATURAL] RETURNS[NATURAL] = MACHINE CODE {
Mopcodes.zLI1; Mopcodes.zADD; Mopcodes.zLINB, 376B; Mopcodes.zAND};
SmashPacketType: PROC[
p: SptpProtocol.Encapsulation, t: SptpProtocol.PacketType] = INLINE
BEGIN
PacketTypeFieldPointer: TYPE = LONG POINTER TO PacketTypeField;
PacketTypeField: TYPE = MACHINE DEPENDENT RECORD[
t(0: 0..7): SptpProtocol.PacketType, r(0: 8..15): BOOLEAN];
LOOPHOLE[p, PacketTypeFieldPointer].t ← t;
END; --SmashPacketType
--********* Protocol State Machine Procedures **********--
ActiveNegotiation: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
timein: LONG CARDINAL = System.GetClockPulses[];
UNTIL (System.GetClockPulses[] - timein) > clock.to3 DO
timeout: LONG CARDINAL ← clock.to1;
SendMyOptions[protocol, TRUE]; --get things rolling
UNTIL (b ← WaitForControl[protocol, timeout]) = NIL DO
ProcessControl[protocol, b];
timeout ← LAST[LONG CARDINAL];
ENDLOOP;
IF protocol.object.state # option1 THEN EXIT; --done here
REPEAT FINISHED => protocol.object.state ← terminate2; --give up
ENDLOOP;
END; --ActiveNegotiation
AwaitingOptions: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
timein: LONG CARDINAL = System.GetClockPulses[];
UNTIL (System.GetClockPulses[] - timein) > clock.to3 DO
timeout: LONG CARDINAL ← clock.to1;
UNTIL (b ← WaitForControl[protocol, timeout]) = NIL DO
ProcessControl[protocol, b];
timeout ← LAST[LONG CARDINAL];
ENDLOOP;
IF protocol.object.state # option3 THEN EXIT; --done here
SendMyOptions[protocol, TRUE]; --ask again
REPEAT FINISHED => protocol.object.state ← terminate2; --give up
ENDLOOP;
END; --AwaitingOptions
AwaitingOptionAck: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
timein: LONG CARDINAL = System.GetClockPulses[];
UNTIL (System.GetClockPulses[] - timein) > clock.to2 DO
timeout: LONG CARDINAL ← clock.to1;
UNTIL (b ← WaitForControl[protocol, timeout]) = NIL DO
ProcessControl[protocol, b];
timeout ← LAST[LONG CARDINAL];
ENDLOOP;
IF protocol.object.state # option4 THEN EXIT; --done here
SendMyOptions[protocol, TRUE]; --ask again
REPEAT FINISHED => protocol.object.state ← terminate2; --give up
ENDLOOP;
END; --AwaitingOptionAck;
AwaitTerminateReply: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
timein: LONG CARDINAL = System.GetClockPulses[];
UNTIL (System.GetClockPulses[] - timein) > clock.to6 DO
timeout: LONG CARDINAL ← clock.to4;
UNTIL (b ← WaitForControl[protocol, timeout]) = NIL DO
ProcessControl[protocol, b]; timeout ← LAST[LONG CARDINAL];
ENDLOOP;
IF protocol.object.state # terminate1 THEN EXIT; --done here
SendTerminateRequest[protocol, TRUE]; --ask again
REPEAT FINISHED => protocol.object.state ← terminate2; --give up
ENDLOOP;
END; --AwaitTerminateReply
EntityClash: PROC[mine, his: SptpProtocol.EntityClass]
RETURNS[BOOLEAN] = INLINE
BEGIN
--returns TRUE of there is a clash
clash: <<PACKED>> ARRAY SptpProtocol.EntityClass OF
<<PACKED>> ARRAY SptpProtocol.EntityClass OF BOOLEAN =
-- inr cnr siu ws
--inr--[[FALSE, FALSE, FALSE, TRUE],
--cnr-- [FALSE, TRUE, TRUE, FALSE],
--siu-- [FALSE, TRUE, TRUE, FALSE],
--ws-- [TRUE, FALSE, FALSE, FALSE]];
RETURN[clash[mine][his]];
END; --EntityClash
FrameSize: PROC[hi, lo: Environment.Byte] RETURNS[va: WORD] = INLINE
{OPEN bn: LOOPHOLE[va, TwoBytes]; bn.hi ← hi; bn.lo ← lo}; --FrameSize
LatchSiu: PROC = INLINE {[] ← SppOps.SetSppSpy[SiuSingleBufferSpy]};
PassiveNegotiation: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
IF (b ← WaitForControl[protocol, clock.to3]) # NIL THEN
ProcessControl[protocol, b];
END; --PassiveNegotiation
ProcessControl: PUBLIC <<SptpProtocol>>
PROC[protocol: SptpProtocol.Protocol, b: Buffer.Buffer] =
BEGIN
WITH encapsulation:
SptpProtocol.EncapsulationFromBlock[b.linkLayer.blockPointer] SELECT FROM
control =>
BEGIN
hisAnswer: SptpProtocol.Control = LOOPHOLE[
@encapsulation + SIZE[control SptpProtocol.EncapsulationObject]];
WITH c: hisAnswer SELECT encapsulation.control FROM
myOptions =>
BEGIN
frameSize: NATURAL = FrameSize[ --may be bogus
c.maxPktSizeHiByte, c.maxPktSizeLowByte];
IF CommFlags.doStats THEN SptpStats.Incr[rcvMyOptions];
SELECT TRUE FROM
(c.highestVersionNumber < pvVersionLow) =>
BEGIN
protocol.object.state ← terminate2; --just drop the line
GOTO returnBufferAndExit; --get out of here
END;
(c.lowestVersionNumber > pvVersionHigh) =>
BEGIN
protocol.object.state ← terminate2; --just drop the line
GOTO returnBufferAndExit; --get out of here
END;
((protocol.object.him ← c.sourceHost) = protocol.object.me) =>
BEGIN
SendAddressReject[protocol]; --that's loopback mode
protocol.object.state ← terminate1; --and it's fatal
GOTO returnBufferAndExit; --get out of here
END;
(EntityClash[protocol.object.ourEntityClass, c.entityClass]) =>
BEGIN
SendClassReject[protocol]; --tell him we're going down
protocol.object.state ← terminate1; --and it's fatal
GOTO returnBufferAndExit; --get out of here
END;
(c.highestVersionNumber > protocol.object.protocolVersion) =>
BEGIN
SendVersionReject[protocol, FALSE]; --but not fatal
SendMyOptions[protocol]; --send my preferences again
GOTO returnBufferAndExit; --get out of here
END;
(frameSize > SptpOps.maxRS232CBytes) =>
BEGIN
SendSizeReject[protocol, FALSE]; --send him the bad news
SendMyOptions[protocol]; --send my preferences again
GOTO returnBufferAndExit; --get out of here
END;
ENDCASE;
IF point5Duplex
AND (protocol.object.duplex = half) THEN
protocol.object.master ← SetMasterSlaveRelationship[
protocol.object.me, protocol.object.him];
protocol.myDevice.receiveBufferLen ← frameSize;
protocol.object.theirEntityClass ← c.entityClass;
protocol.object.protocolVersion ← c.highestVersionNumber;
SELECT protocol.object.state FROM
option1, option2 =>
BEGIN
protocol.object.started ← System.GetGreenwichMeanTime[];
protocol.object.state ← option4; --advance the state
SendOptionsAck[protocol, FALSE]; --but we can ack him
SendMyOptions[protocol, TRUE]; --we're not in data yet
END;
option3 =>
BEGIN
protocol.object.established ← System.GetGreenwichMeanTime[];
IF CommFlags.driverStats THEN
BEGIN
OPEN s: NARROW[protocol.myDevice.stats, StatsPointer];
s.protocolUp ← s.protocolUp.SUCC;
END;
protocol.myDevice.alive ← TRUE; --what we were waiting for
protocol.object.state ← data; --and we're up
SendOptionsAck[protocol]; --ack him
SELECT TRUE FROM
(~SptpOps.siuSupport) => NULL; --this isn't necessary
(protocol.object.theirEntityClass = siu) => LatchSiu[];
ENDCASE => UnlatchSiu[];
END;
option4 =>
BEGIN
SendOptionsAck[protocol, FALSE]; --ack him again
SendMyOptions[protocol, TRUE]; --another copy of options
END;
data => SendOptionsAck[protocol]; --ack him again
ENDCASE;
END;
optionsAck =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvOptionsAck];
IF c.destinationHost # protocol.object.me THEN
BEGIN
SendAddressReject[protocol];
protocol.object.state ← terminate1;
END
ELSE
BEGIN
SELECT protocol.object.state FROM
option1 =>
BEGIN
protocol.object.started ← System.GetGreenwichMeanTime[];
protocol.object.state ← option3; --advance state
SendMyOptions[protocol]; --send him another copy
END;
option3 => SendMyOptions[protocol]; --send him another copy
option4 =>
BEGIN
IF CommFlags.driverStats THEN
BEGIN
OPEN s: NARROW[protocol.myDevice.stats, StatsPointer];
s.protocolUp ← s.protocolUp.SUCC;
END;
protocol.object.established ← System.GetGreenwichMeanTime[];
protocol.myDevice.alive ← TRUE; --what we were waiting for
protocol.object.state ← data; --and we're up
SendMyOptions[protocol]; --send him another copy
SELECT TRUE FROM
(~SptpOps.siuSupport) => NULL; --this isn't necessary
(protocol.object.theirEntityClass = siu) => LatchSiu[];
ENDCASE => UnlatchSiu[];
END;
ENDCASE => SendNull[protocol]; --to provide LTA if needed
END;
END;
terminateRequest =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvTermReq];
SendTerminateReply[protocol]; --so reply to him
protocol.myDevice.alive ← FALSE; --we're dropping out
protocol.object.state ← terminate2; --he wants to quit
END;
terminateReply =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvTermRep];
protocol.myDevice.alive ← FALSE; --we're dropping out
protocol.object.state ← terminate2; --he knows we want to quit
END;
versionReject =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvVersionReject];
protocol.object.protocolVersion ← c.highestVersionNumber;
--protocol state should be active negotiation - still
END;
areYouThere =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvYouThere];
SELECT protocol.object.state FROM
data => SendIAmHere[protocol];
terminate1, terminate2 => SendTerminateRequest[protocol];
ENDCASE => SendMyOptions[protocol]; --somewhere in options
END;
addressReject =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvAddrReject];
SendTerminateRequest[protocol]; --okay, we'll give up
protocol.object.state ← terminate1; --and get out of this state
END;
classReject =>
BEGIN
IF CommFlags.doStats THEN SptpStats.Incr[rcvClassReject];
SendTerminateRequest[protocol]; --okay, we'll give up
protocol.object.state ← terminate1; --and get out of this state
END;
null => IF CommFlags.doStats THEN SptpStats.Incr[rcvNull];
ENDCASE; --don't know what it was, but I'm going to ignore it
EXITS returnBufferAndExit => NULL;
END;
ENDCASE;
Driver.ReturnFreeBuffer[b]; --return the buffer
END; --ProcessControl
SendAddressReject: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
addressRejectLength: NATURAL = 2;
AddressReject: TYPE = LONG POINTER TO AddressRejectFrame;
AddressRejectFrame: TYPE = RECORD[
encapsulation: SptpProtocol.EncapsulationObject.control,
options: SptpProtocol.ControlBody.addressReject];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, AddressReject].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: addressReject]];
protocol.sendControlFrame[b, addressRejectLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtAddrReject];
END; --SendAddressReject
SendAreYouThere: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
areYouThereLength: NATURAL = 2;
AreYouThere: TYPE = LONG POINTER TO AreYouThereFrame;
AreYouThereFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: areYouThere SptpProtocol.ControlBody];
IF (b ← Driver.GetInputBuffer[FALSE, SptpOps.minRS232CBytes]) = NIL THEN
RETURN; --not too serious about sending this one
LOOPHOLE[b.linkLayer.blockPointer, AreYouThere].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: areYouThere]];
protocol.sendControlFrame[b, areYouThereLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtYouThere];
END; --SendAreYouThere
SendClassReject: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
classRejectLength: NATURAL = 2;
ClassReject: TYPE = LONG POINTER TO ClassRejectFrame;
ClassRejectFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: classReject SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, ClassReject].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: classReject]];
protocol.sendControlFrame[b, classRejectLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtClassReject];
END; --SendClassReject
SendIAmHere: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
iAmHereLength: NATURAL = 2;
IAmHere: TYPE = LONG POINTER TO IAmHereFrame;
IAmHereFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: iAmHere SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, IAmHere].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: iAmHere]];
protocol.sendControlFrame[b, iAmHereLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtIHere];
END; --SendIAmHere
SendMyOptions: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
myOptionsLength: NATURAL = 13;
MyOptions: TYPE = LONG POINTER TO MyOptionsFrame;
MyOptionsFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: myOptions SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, MyOptions]↑ ← [
encapsulation: [control[LTA: lta, reserved: FALSE, control: myOptions]],
options: [myOptions[
highestVersionNumber: protocol.object.protocolVersion,
lowestVersionNumber: pvVersionLow,
sourceHost: protocol.object.me,
entityClass: protocol.object.ourEntityClass,
maxPktSizeHiByte: Inline.HighByte[SptpOps.maxRS232CBytes],
maxPktSizeLowByte: Inline.LowByte[SptpOps.maxRS232CBytes]]]];
protocol.sendControlFrame[b, myOptionsLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtMyOptions];
END; --SendMyOptions
SendNull: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
IF point5Duplex AND (protocol.object.duplex = half) THEN
BEGIN
b: Buffer.Buffer;
nullFrameLength: NATURAL = 2;
Null: TYPE = LONG POINTER TO NullFrame;
NullFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: null SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, Null].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: null]];
protocol.sendControlFrame[b, nullFrameLength]; --now send the buffer
END;
END; --SendNull
SendOptionsAck: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
optionsAckLength: NATURAL = 8;
OptionsAck: TYPE = LONG POINTER TO OptionsAckFrame;
OptionsAckFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: optionsAck SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, OptionsAck]↑ ← [
encapsulation: [control[
LTA: lta, reserved: FALSE, control: optionsAck]],
options: [optionsAck[IF protocol.object.theirEntityClass = siu THEN
protocol.object.me ELSE protocol.object.him]]];
protocol.sendControlFrame[b, optionsAckLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtOptionsAck];
END; --SendOptionsAck
SendSizeReject: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
sizeRejectLength: NATURAL = 2;
SizeReject: TYPE = LONG POINTER TO SizeRejectFrame;
SizeRejectFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: sizeReject SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, SizeReject].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: sizeReject]];
protocol.sendControlFrame[b, sizeRejectLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtSizeReject];
END; --SendSizeReject
SendTerminateRequest: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
terminateRequestLength: NATURAL = 2;
TerminateRequest: TYPE = LONG POINTER TO TerminateRequestFrame;
TerminateRequestFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: terminateRequest SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, TerminateRequest].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: terminateRequest]];
protocol.sendControlFrame[b, terminateRequestLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtTermReq];
END; --SendTerminateRequest
SendTerminateReply: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
terminateReplyLength: NATURAL = 2;
TerminateReply: TYPE = LONG POINTER TO TerminateReplyFrame;
TerminateReplyFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: terminateReply SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, TerminateReply].encapsulation ←
[control[LTA: lta, reserved: FALSE, control: terminateReply]];
protocol.sendControlFrame[b, terminateReplyLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtTermRep];
END; --SendTerminateReply
SendVersionReject: SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
versionRejectLength: NATURAL = 3;
VersionReject: TYPE = LONG POINTER TO VersionRejectFrame;
VersionRejectFrame: TYPE = RECORD[
encapsulation: control SptpProtocol.EncapsulationObject,
options: versionReject SptpProtocol.ControlBody];
UNTIL (b ← Driver.GetInputBuffer[TRUE, SptpOps.minRS232CBytes]) # NIL
DO ENDLOOP;
LOOPHOLE[b.linkLayer.blockPointer, VersionReject]↑ ← [
encapsulation: [control[
LTA: lta, reserved: FALSE, control: versionReject]],
options: [versionReject[
highestVersionNumber: protocol.object.protocolVersion]]];
protocol.sendControlFrame[b, versionRejectLength];
IF CommFlags.doStats THEN SptpStats.Incr[xmtVersionReject];
END; --SendVersionReject
SetMasterSlaveRelationship: PROC[me, him: System.HostNumber]
RETURNS[SptpProtocol.MasterSlaveRelationship] = --INLINE
BEGIN
OPEN m: LOOPHOLE[me, Forty8Bitter], h: LOOPHOLE[him, Forty8Bitter];
RETURN[SELECT TRUE FROM
(him = System.nullHostNumber) => him, --stupid ole SIU?
(h.one > m.one) => him, (h.one < m.one) => me,
(h.two > m.two) => him, (h.two < m.two) => me,
(h.three > m.three) => him, (h.three < m.three) => me,
ENDCASE => me]; --and if they're equal, welllllll!
END; --SetMasterSlaveRelationship
SiuSingleBufferSpy: SppOps.SppSpyProc =
BEGIN
IF SptpOps.siuSupport THEN
BEGIN
gf: LONG POINTER TO FRAME[NetworkStreamImpl] ← LOOPHOLE[link];
IF action = create THEN
BEGIN
gf.xmtr.maxAlloc ← 0; --that's the most we'll try to send
gf.rcvr.maxAlloc ← 0; --that's the most we want sent to us
gf.rexmtr.interval ← System.MicrosecondsToPulses[6000000];
END;
END;
END; --SiuSingleBufferSpy
TerminationDally: PUBLIC <<SptpProtocol>> SptpProtocol.ProtocolProc =
BEGIN
b: Buffer.Buffer;
UNTIL (b ← WaitForControl[protocol, clock.to5]) = NIL DO
ProcessControl[protocol, b]; --keep this up until he quits
ENDLOOP;
protocol.object.state ← idle; --now I'm idle
END; --TerminationDally
UnlatchSiu: PROC = INLINE {[] ← SppOps.SetSppSpy[NIL]};
WaitForControl: PUBLIC ENTRY <<SptpProtocol LOCKS protocol.lock↑>>
PROC[protocol: SptpProtocol.Protocol, timeout: LONG CARDINAL]
RETURNS[Buffer.Buffer] =
BEGIN
ENABLE UNWIND => NULL;
timein: LONG CARDINAL = System.GetClockPulses[]; --when we enter
WHILE protocol.q.length = 0 DO --already have something to do
IF timeout = LAST[LONG CARDINAL] THEN EXIT; --just checking queue
WAIT protocol.engine; --wait for a notable event
SELECT TRUE FROM
(protocol.q.length > 0) => EXIT; --we can do it now
(timeout = 0) => EXIT; --just waiting for the interrupt
((System.GetClockPulses[] - timein) > timeout) => EXIT; --timeout
ENDCASE;
ENDLOOP;
RETURN[Buffer.Dequeue[@protocol.q]];
END; --WaitForControl
clock.to1 ← System.MicrosecondsToPulses[2D6]; --2 seconds
clock.to2 ← System.MicrosecondsToPulses[20D6]; --20 secs
clock.to3 ← System.MicrosecondsToPulses[10D6]; --10 secs
clock.to4 ← System.MicrosecondsToPulses[5D6]; --5 secs
clock.to5 ← System.MicrosecondsToPulses[2D6]; --2 seconds
clock.to6 ← System.MicrosecondsToPulses[20D6]; --20 secs
END..
LOG
29-Sep-87 18:32:20 AOF Created file.
2-Nov-87 12:23:10 AOF Adjusting window for SIUs.
7-Nov-87 16:24:09 AOF Moved in state machine procs from SptpDriver.
11-Nov-87 19:07:53 AOF Export missing procedures and error.
13-Nov-87 12:00:54 AOF Mods to Adoption routines.
2-Dec-87 14:48:24 AOF State machine cleanup.
2-Dec-87 15:48:30 AOF Set master-slave relationship sooner.
15-Dec-87 13:24:41 AOF SIUs - they don't use same encapsulation.
18-Jan-88 14:38:49 AOF Sutting down allocation for SIUs.
3-Feb-88 11:26:19 AOF PupGateway (no .5 duplex).