// BFSEvent.bcpl -- monitor a BFS using the Pup Event Report Protocol // Copyright Xerox Corporation 1979 // Last modified May 29, 1979 11:52 PM by Boggs get "AltoFileSys.d" get "AltoDefs.d" get "Disks.d" get "BFS.d" external [ // outgoing procedures BFSEvent // incoming procedures Timer; Zero; MoveBlock; StartIO; Idle ] static [ // a very degenerate routing table: lclNet // our net number, last time we got a routing packet lclHost // our host number, last time we reset the interface frnNet // net number of our partner gateHost // gateway host to get to frnNet BFSEventHost = 0 // non-zero => generate Event Reports to this address ] //---------------------------------------------------------------------------- structure Port: // Internetwork address //---------------------------------------------------------------------------- [ net byte host byte socket^1,2 word ] manifest lenPort = size Port/16 //---------------------------------------------------------------------------- structure PBI: // A Pup in an Ethernet packet //---------------------------------------------------------------------------- [ eDest byte // destination on this Ethernet eSrc byte // my address on this Ethernet eType word // 1000B => Pup // the Pup begins here, stuff above is Ethernet encapsulation length word // Bytes of pup contents + header transport byte // zero it on sending type byte // pup type id word 2 // generally used for duplicate detection dPort: @Port // internet destination address of this packet sPort: @Port // internet source address of this packet bytes^0,531 byte // the data checksum word // position varies -- follows contents ] manifest lenPBI = size PBI/16 //---------------------------------------------------------------------------- structure RTE: // Routing table entry //---------------------------------------------------------------------------- [ dNet byte // to get to this net... viaNet byte // if zero I'm directly connected; send them to me viaHost byte // if non zero, I'll send them here hops byte // your goal is this many internet hops away ] manifest lenRTE = size RTE/16 //---------------------------------------------------------------------------- structure RTPBI: // Routing table PBI //---------------------------------------------------------------------------- [ blank word offset PBI.bytes/16 rte^0,0 @RTE ] //---------------------------------------------------------------------------- structure BFSPBI: // BFSEvent PBI //---------------------------------------------------------------------------- [ blank word offset PBI.bytes/16 kcb @KCB label @DL ] manifest lenBFSPBI = size BFSPBI/16 manifest [ pupOvBytes = 22 // Pup header overhead ptEventReport = 240B // Pup Types ptEventReply = 241B ptRouteRequest = 200B ptRouteReply = 201B socRouteInfo = 2 // Well known sockets // Ether definitions etherPup = 1000B // Ethernet type = Pup ePLoc = 600B // Ending status eBLoc = 601B // Interrupt channel bits eELoc = 602B // Ending count eLLoc = 603B // Initial load eICLoc = 604B // Input count eIPLoc = 605B // Input pointer eOCLoc = 606B // Output count eOPLoc = 607B // Output pointer eHLoc = 610B // Host address etherReset = 3 // interface SIO command bits etherInput = 2 etherOutput = 1 ] //---------------------------------------------------------------------------- let BFSEvent(cb) be //---------------------------------------------------------------------------- [ if BFSEventHost eq 0 return let origTim = vec 2; Timer(origTim) let sPort = table [ 0; 0; 123456b ] let dPort = table [ 0; 0; 123456b ] dPort>>Port.host = BFSEventHost let pbi = vec lenPBI for try = 1 to 3 do [ MoveBlock(lv pbi>>BFSPBI.kcb, lv cb>>CB.link, lKCB) MoveBlock(lv pbi>>BFSPBI.label, cb>>CB.labelAddress, lDL) SendPup(pbi, sPort, dPort, origTim, ptEventReport, lenBFSPBI*2) if ReceivePup(pbi, dPort, sPort, origTim, ptEventReply, 27) break ] ] //---------------------------------------------------------------------------- and InitNet() = valof //---------------------------------------------------------------------------- [ @eHLoc = StartIO(etherReset) if @eHLoc & 77777b eq 0 resultis false @eHLoc = @eHLoc & 377b if @eHLoc eq 0 resultis false Zero(ePLoc, 7) if @eHLoc ne lclHost then lclNet = 0 lclHost = @eHLoc resultis true ] //---------------------------------------------------------------------------- and SendPup(pbi, sPort, dPort, id, type, length) = valof //---------------------------------------------------------------------------- // Assume data already in pbi. // Returns true if packet seemed to go out OK. [ unless InitNet() resultis false if dPort ne 0 then MoveBlock(lv pbi>>PBI.dPort, dPort, lenPort) if sPort ne 0 then MoveBlock(lv pbi>>PBI.sPort, sPort, lenPort) if id ne 0 then MoveBlock(lv pbi>>PBI.id, id, 2) let dNet = pbi>>PBI.dPort.net test dNet eq 0 % dNet eq lclNet ifso pbi>>PBI.eDest = pbi>>PBI.dPort.host ifnot test dNet eq frnNet & gateHost ne 0 ifso pbi>>PBI.eDest = gateHost ifnot [ frnNet, gateHost = dNet, 0 let rPort = table [ 0; 0; socRouteInfo ] SendPup(pbi, rPort, rPort, 0, ptRouteRequest, pupOvBytes) resultis true //Liar! And you dirtied his packet too! ] pbi>>PBI.eSrc = @eHLoc pbi>>PBI.eType = etherPup // I'm a Pup in an Ether packet pbi>>PBI.length = length pbi>>PBI.transport = 0 pbi>>PBI.type = type pbi>>PBI.sPort.net = lclNet pbi>>PBI.sPort.host = @eHLoc pbi!((length+3) rshift 1) = -1 // No checksum @eOCLoc = (length+5) rshift 1 // Pup bytes + Ethernet encapsulation @eOPLoc = pbi @ePLoc = 0 StartIO(etherOutput) // Turn on transmitter for i = 1 to 30000 if @ePLoc ne 0 break let status = @ePLoc StartIO(etherReset) // Reset interface resultis status eq 777b // 777b is good xmtr status ] //---------------------------------------------------------------------------- and ReceivePup(pbi, sPort, dPort, id, type, timeout) = valof //---------------------------------------------------------------------------- // Filter by sockets, id, and type. // Returns pup length or 0 if timeout. [ unless InitNet() resultis false let tim = @realTimeClock + timeout [ @eICLoc = lenPBI @eIPLoc = pbi @ePLoc = 0 StartIO(etherInput) // Turn on receiver while @ePLoc eq 0 & (tim - @realTimeClock) gr 0 do Idle() let lastEPLoc = @ePLoc let lastEELoc = @eELoc StartIO(etherReset) // Reset interface if lastEPLoc eq 0 resultis 0 // timeout // reject obviously bad packets if (@eICLoc-lastEELoc) ne (pbi>>PBI.length+5) rshift 1 % lastEPLoc ne 377b % pbi>>PBI.eType ne etherPup % pbi>>PBI.eSrc eq 0 loop if EqV(lv pbi>>PBI.dPort.socket, table [ 0; socRouteInfo ], 2) & pbi>>PBI.type eq ptRouteReply then [ // sort of a 'built-in' socket... lclNet = pbi>>PBI.dPort.net for i = 0 to (pbi>>PBI.length-pupOvBytes)/lenRTE do if pbi>>RTPBI.rte^i.dNet eq frnNet then [ gateHost = pbi>>PBI.sPort.host; break ] loop ] if (type eq 0? true, pbi>>PBI.type eq type) & EqV(lv pbi>>PBI.sPort.socket, lv sPort>>Port.socket, 2) & EqV(lv pbi>>PBI.dPort.socket, lv dPort>>Port.socket, 2) & EqV(lv pbi>>PBI.id, id, 2) resultis pbi>>PBI.length ] repeat // Until good Pup received or timeout ] //---------------------------------------------------------------------------- and EqV(a, b, len) = valof //---------------------------------------------------------------------------- [ if (b & 177770B) eq 0 resultis true // Don't compare for i = 0 to len-1 do if a!i ne b!i resultis false resultis true ]