// IfsSequinSwap.bcpl - Sequin - SWAPPABLE // Copyright Xerox Corporation 1979, 1980, 1981, 1982 // Last modified by September 5, 1982 12:32 PM by Taft get ecOutOfSequence, ecVPBIBackChain, ecSequinError from "IfsLeafErrors.decl"; get "IfsLeaf.decl"; get "IfsSequin.decl"; external [ //outgoing procedures HandleLeafRejection; SequenceCompare; SequinCtx; SequinBreak; SequinDestroy; SequinReset; //incoming procedures SysAllocate; SysAllocateZero; SysFree; Block; CompletePup; Dequeue; DoubleIncrement; Enqueue; ExchangePorts; FindLockedSequin; IFSError; LeafFinish; LockSequin; MoveBlock; ReadVPBI; ReleaseVPBI; ReleasePBI; SequinInput; SequinKickReaper; SequinStartOutput; SetTimer; TimerHasExpired; UnlockSequin; Zero; //incoming statics entFlag; haltFlag; leafEnabled; lenPup sequinAnomalies; scb; socLeaf; ] static sequinDebug = false; //---------------------------------------------------------------------------- let SequinCtx() be //---------------------------------------------------------------------------- [ let timer = nil; let noActivity = nil; [ // repeat [ let pbi = Dequeue(lv socLeaf>>PupSoc.iQ); if pbi eq 0 break; // Allow for retransmit activity SetTimer(lv timer, activityTimeout); noActivity = false; if pbi>>PBI.pup.type ne typeLeaf then [ ReleasePBI(pbi); loop; ] let sequin = FindLockedSequin(lv pbi>>PBI.pup.sPort); if sequin eq 0 then sequin = OpenSequin(pbi); if sequin eq 0 loop; HandlePBI(pbi, sequin); UnlockSequin(sequin); ] repeat Block(); noActivity = noActivity % TimerHasExpired(lv timer); ] repeatuntil scb>>SCB.sequinQ.head eq 0 & noActivity LeafFinish(); // Doesn't return; ] //---------------------------------------------------------------------------- and OpenSequin(pbi) = valof //---------------------------------------------------------------------------- [ if (lv pbi>>PBI.pup.id)>>SequinID.control ne sequinOpen then [ SequinAnswer(0, pbi, sequinBroken); resultis 0; ] if haltFlag % not (leafEnabled & entFlag) then [ LeafRFCFail(pbi); resultis 0; ] // Note that openState = 0, sequinData = 0...initial state. let sequin = SysAllocateZero(lenSequin); MoveBlock(lv sequin>>Sequin.port, lv pbi>>PBI.pup.sPort, lenPort); sequin>>Sequin.pupDataBytes = 2*lenPup - pupOvBytes; sequin>>Sequin.lockTimeout = defaultLockTimeout; sequin>>Sequin.connTimeout = defaultConnTimeout; sequin>>Sequin.allocate = maxInputVPBIs; sequin>>Sequin.inputLink = -1; sequin>>Sequin.outputLink = -1; Enqueue(lv scb>>SCB.sequinQ, sequin); LockSequin(sequin); DoubleIncrement(lv scb>>SCB.acceptedRFCs); resultis sequin; ] //---------------------------------------------------------------------------- and HandlePBI(pbi, sequin) be //---------------------------------------------------------------------------- [ let pbiID = lv pbi>>PBI.pup.id; let control = pbiID>>SequinID.control; // Open, close are also sequenced data packets. if control eq sequinOpen % control eq sequinClose then control = sequinData; // check pbi's send sequence switchon SequenceCompare(pbiID>>SequinID.sendSequence, sequin>>Sequin.receiveSequence) into [ case outOfRange: SequinError(sequin, pbi); return; case ahead: SequinAnswer(sequin, pbi, sequinRestart); return; case duplicate: [ if SequenceCompare(pbiID>>SequinID.sendSequence + 1, // the latest? sequin>>Sequin.receiveSequence) ne equal % control ne sequinData then [ ReleasePBI(pbi); return; ] // no, ignore it control = sequinRestart; // yes, make it a restart ] ] // equal sequence..(or fake restart) //copy the allocate (N.B. not ordered between data and controlData messages) sequin>>Sequin.allocated = pbiID>>SequinID.allocate // handle any acks let ackedSequence = sequin>>Sequin.ackedState.current; switchon SequenceCompare(pbiID>>SequinID.receiveSequence, ackedSequence) into [ // Careful!! Sequence numbers are 8 bits in the pbi, 16 in the sequin. case ahead: [ let newAckedSeq = ackedSequence + ((pbiID>>SequinID.receiveSequence - ackedSequence) & #377); if (newAckedSeq - sequin>>Sequin.sendSequence) gr 0 then docase outOfRange; sequin>>Sequin.ackedState.current = newAckedSeq; SequinKickReaper(sequin); unless sequin>>Sequin.retransmitting do SequinHandleAcks(sequin); endcase; ] case outOfRange: SequinError(sequin, pbi); return; case duplicate: ReleasePBI(pbi); return; ] // act on state conditions switchon sequin>>Sequin.state into [ case closedState: // check original control op in packet for transition to openState. if pbiID>>SequinID.control ne sequinData then docase openState; case timedOutState: sequin>>Sequin.control = sequinData; sequin>>Sequin.state = openState; case openState: sequin>>Sequin.timerCount = sequin>>Sequin.lockTimeout; // Reset timer endcase; case brokenState: SequinAnswer(sequin, pbi, sequinBroken); return; case dallyingState: unless control eq sequinQuit do [ SequinAnswer(sequin, pbi, sequinDallying); return; ] SequinDestroy(sequin); case destroyedState: ReleasePBI(pbi); return; ] // dispatch on control field // guaranteed either open or closed state here switchon control into [ case sequinDestroy: [ sequin>>Sequin.state = dallyingState; SequinAnswer(sequin, pbi, sequinDallying); endcase; ] case sequinCheck: case sequinNop: SequinAnswer(sequin, pbi, sequinAck); endcase; case sequinRestart: [ if sequin>>Sequin.sendSequence ne sequin>>Sequin.ackedState.current do [ sequin>>Sequin.retransmitting = true; SequinStartOutput(sequin); ] // fall through ] case sequinAck: ReleasePBI(pbi); endcase; case sequinData: [ if sequin>>Sequin.state ne openState then docase sequinStateError; if pbiID>>SequinID.control eq sequinClose then [ sequin>>Sequin.control = sequinClosed; sequin>>Sequin.state = closedState; ] sequin>>Sequin.haltTimerCount = haltTimeout; if pbi>>PBI.pup.length eq pupOvBytes then [ SequinAnswer(sequin, pbi); endcase; ] SequinInput(sequin, pbi); ReleasePBI(pbi); endcase; ] case sequinBreak: case sequinRetransmit: // requires keeping two retransmitQueue's case sequinStateError: default: SequinError(sequin, pbi); ] ] //---------------------------------------------------------------------------- and SequenceCompare(this, that) = valof //---------------------------------------------------------------------------- [ let diff = (this - that) & #377 if diff eq 0 resultis equal if diff le maxGetAheadVPBIs resultis ahead if diff ge #377 - maxGetAheadVPBIs resultis duplicate resultis outOfRange ] //---------------------------------------------------------------------------- and SequinHandleAcks(sequin) be //---------------------------------------------------------------------------- [ let sequence = sequin>>Sequin.sendSequence; let ackedSequence = sequin>>Sequin.ackedState.current; let vecLength = ackedSequence - sequin>>Sequin.ackedState.reaped; if vecLength eq 0 return; let id = sequin>>Sequin.lastSendVPBIID; let ackedVec = SysAllocate(vecLength); let vecIndex = 0; [ // Scan the backward chain here. sequence = sequence - 1; if ackedSequence - sequence gr 0 then [ if vecIndex ge vecLength then IFSError(ecVPBIBackChain); ackedVec!vecIndex = id; vecIndex = vecIndex + 1; ] let diff = sequence - sequin>>Sequin.ackedState.reaped; if diff eq 0 break; if diff ls 0 then [ vecIndex = vecIndex + diff; break; ] let vpbi = ReadVPBI(id, cleanPage + inCoreOp, true); if vpbi eq 0 then [ SysFree(ackedVec); return; ] if sequence ne vpbi>>VPBI.sequence then IFSError(ecOutOfSequence); id = vpbi>>VPBI.backChain; ] repeat // Release the vpbis here! until vecIndex eq 0 do [ vecIndex = vecIndex - 1; let vpbi = ReadVPBI(ackedVec!vecIndex, dirtyPage + inCoreOp, true); if vpbi eq 0 break; ReleaseVPBI(vpbi); ] SysFree(ackedVec); ] //---------------------------------------------------------------------------- and SequinAnswer(sequin, pbi, control; numargs na) be //---------------------------------------------------------------------------- [ // N.B. This is the only place where CompletePup can be called with a real PBI // This should never be called with na ls 3 and sequin = 0; let pbiID = lv pbi>>PBI.pup.id; if sequin ne 0 then [ pbiID>>SequinID.allocate = sequin>>Sequin.allocate - sequin>>Sequin.freeInputSlot; pbiID>>SequinID.receiveSequence = sequin>>Sequin.receiveSequence pbiID>>SequinID.sendSequence = sequin>>Sequin.sendSequence if na ls 3 then control = sequin>>Sequin.control; ] pbiID>>SequinID.control = control; ExchangePorts(pbi); CompletePup(pbi, typeLeaf, pupOvBytes); ] //---------------------------------------------------------------------------- and HandleLeafRejection() be //---------------------------------------------------------------------------- [ let pbi = Dequeue(lv socLeaf>>PupSoc.iQ); if pbi eq 0 return; test pbi>>PBI.pup.type eq typeLeaf & (lv pbi>>PBI.pup.id)>>SequinID.control eq sequinOpen ifso LeafRFCFail(pbi) ifnot ReleasePBI(pbi); ] repeat //---------------------------------------------------------------------------- and LeafRFCFail(pbi) be //---------------------------------------------------------------------------- [ DoubleIncrement(lv scb>>SCB.refusedRFCs); SequinAnswer(0, pbi, sequinBroken); // *** More info to user later. ] //---------------------------------------------------------------------------- and SequinBreak(sequin) be //---------------------------------------------------------------------------- [ sequin>>Sequin.state = brokenState; sequin>>Sequin.control = sequinBroken; ] //---------------------------------------------------------------------------- and SequinDestroy(sequin) be //---------------------------------------------------------------------------- [ sequin>>Sequin.state = destroyedState; SequinKickReaper(sequin); ] //---------------------------------------------------------------------------- and SequinError(sequin, pbi) be //---------------------------------------------------------------------------- [ if sequinDebug then IFSError(ecSequinError); SequinBreak(sequin); SequinAnswer(sequin, pbi); ] //---------------------------------------------------------------------------- and SequinReset(sequin) be //---------------------------------------------------------------------------- [ test sequin>>Sequin.fhQ.head eq 0 ifso SequinDestroy(sequin); ifnot [ sequin>>Sequin.state = timedOutState; Zero(lv sequin>>Sequin.port.socket, 2) ] ]