// GateForward.bcpl -- Level 1 code implementing gateway functions // Last modified February 8, 1979 3:33 PM by Boggs get "Pup0.decl" get "Pup1.decl" get "GateForward.decl" external [ // outgoing procedures Forwarder; ForwarderCtx; TMLookup // incoming procedures GetPBI; ReleasePBI; PupError; ExchangePorts; CompletePup; RoutePup OnesComplementAdd; OnesComplementSubtract; LeftCycle SetTimer; TimerHasExpired; DoubleIncrement; MoveBlock CallSwat; Block; Enqueue; Dequeue; HEnumerate; HHash // outgoing statics @gf; gatewayGoingDown // incoming statics pupRT; pbiFreeQ; unknownNet ndbQ; gatewayListenerSoc maxPupDataBytes; pupRTChanged ] static [ @gf; gatewayGoingDown = false ] //---------------------------------------------------------------------------- let ForwarderCtx() be //---------------------------------------------------------------------------- [ Block() while gf>>GF.tQ.head ne 0 do [ let pbi = Dequeue(lv gf>>GF.tQ) pbi>>PBI.ndb>>NDB.numGPBI = pbi>>PBI.ndb>>NDB.numGPBI +1 ReleasePBI(pbi) ] // time to broadcast routing information? if TimerHasExpired(lv gf>>GF.routeBcstTimer) % pupRTChanged then [ let pbi = GetPBI(gatewayListenerSoc, true) if pbi ne 0 then [ pupRTChanged = false pbi>>PBI.allNets = true pbi>>PBI.bypassZeroNet = true SendRouteInfo(pbi) SetTimer(lv gf>>GF.routeBcstTimer, routeBcstInterval) ] ] // are there any packets to forward? let pbi = Dequeue(lv gf>>GF.iQ); if pbi eq 0 return // Pup destination and source nets let dNet, sNet = pbi>>PBI.pup.dPort.net, pbi>>PBI.pup.sPort.net let psn = pbi>>PBI.ndb>>NDB.localNet //Physical source net //We are experimentally allowing 'directed broadcasts': broadcast packets // destined for a net OTHER THAN THE ONE ON WHICH THEY ARRIVE. test dNet eq 0 % sNet eq 0 % //dest or source net unspecified? (pbi>>PBI.pup.dPort.host eq 0 & dNet eq pbi>>PBI.ndb>>NDB.localNet) ifso ReleasePBI(pbi) //don't forward ifnot [ let v = pbi!(offset PBI.pup.transport/16) pbi>>PBI.pup.hopCnt = pbi>>PBI.pup.hopCnt+1 test pbi>>PBI.pup.hopCnt eq 0 ifso PupError(pbi, 1004b, "Discarded by 8th gateway") ifnot [ UpdatePupChecksum(lv pbi>>PBI.pup, offset Pup.transport/16, v) pbi>>PBI.queue = lv gf>>GF.tQ //where to queue when done let pdh = RoutePup(pbi) //try to route it let ndb = pbi>>PBI.ndb test ndb ne 0 //do we know how to route it? ifso test ndb>>NDB.numGPBI gr 0 //is there room? ifnot PupError(pbi, 1007b, "Gateway OQ overflow") ifso [ ndb>>NDB.numGPBI = ndb>>NDB.numGPBI -1 (ndb>>NDB.encapsulatePup)(pbi, pdh) (ndb>>NDB.level0Transmit)(pbi) TMIncrement(psn, ndb>>NDB.localNet) loop ] ifnot [ //don't know how to route to dNet unknownNet = dNet //initiate a probe ReleasePBI(pbi) //discard ] ] ] TMIncrement(psn, 0) //increment discarded count for psn ] repeat //---------------------------------------------------------------------------- and Forwarder(pbi) be //---------------------------------------------------------------------------- // PupRoute passes on PBIs (from Socket 2) which it doesn't handle. [ ExchangePorts(pbi) // do this here rather than in each case switchon pbi>>PBI.pup.type into [ case ptRouteRequest: [ //don't answer probes from networks whose identity we don't know if pbi>>PBI.pup.dPort.net ne 0 then [ SendRouteInfo(pbi) DoubleIncrement(lv gf>>GF.stats.routeReqs) return ] endcase ] case ptStatsRequest: [ let stats = lv pbi>>PBI.pup.words MoveBlock(lv pbi>>PBI.pup.words, lv gf>>GF.stats, lenStats) let ptr = lenStats +1 let ndb = ndbQ!0; while ndb ne 0 do [ //skip nets whose identity we don't know if ndb>>NDB.localNet ne 0 then [ stats>>Stats.numNets = stats>>Stats.numNets +1 pbi>>PBI.pup.words↑ptr = ndb>>NDB.localNet ptr = ptr +1 ] ndb = ndb>>NDB.link ] //if anybody else needs TMEnumerate, rewrite this procedure for i = 0 to (1 lshift gf>>GF.tm>>TM.logSize)-1 do if gf>>GF.tm>>TM.TME↑i.sdNet ne -1 then [ if (ptr+lenTME-1) gr (maxPupDataBytes rshift 1) break stats>>Stats.numTMEs = stats>>Stats.numTMEs +1 MoveBlock(lv pbi>>PBI.pup.words↑ptr, lv gf>>GF.tm>>TM.TME↑i.sdNet, lenTME) ptr = ptr + lenTME ] CompletePup(pbi, ptStatsReply, pupOvBytes + (ptr-1) lshift 1) return ] ] ReleasePBI(pbi) ] //---------------------------------------------------------------------------- and UpdatePupChecksum(pup, index, oldValue) be //---------------------------------------------------------------------------- // Update Pup checksum to account for changing one word in the Pup // Typical call (changing Transport byte): // let oldWord = pup!(offset Pup.transport/16) // pup>>Pup.transport = newValue // UpdatePupChecksum(pup, offset Pup.transport/16, oldWord) [ let len = (pup>>Pup.length-1) rshift 1 if pup!len ne -1 then pup!len = OnesComplementAdd(pup!len, LeftCycle(OnesComplementSubtract(pup!index, oldValue), len-index)) ] //---------------------------------------------------------------------------- and SendRouteInfo(pbi) be //---------------------------------------------------------------------------- // Build and send a routing info packet in pbi. // Caller is assumed to have fixed up the ports properly. [ pbi>>PBI.pup.length = 0 HEnumerate(pupRT, PerRTE, pbi) CompletePup(pbi, ptRouteReply, pbi>>PBI.pup.length+pupOvBytes) ] //---------------------------------------------------------------------------- and PerRTE(rte, pbi) be //---------------------------------------------------------------------------- [ if rte>>RTE.net ne 0 then [ let c = pbi>>PBI.pup.length pbi>>PBI.pup.bytes↑(c+1) = rte>>RTE.net pbi>>PBI.pup.bytes↑(c+2) = rte>>RTE.ndb>>NDB.localNet pbi>>PBI.pup.bytes↑(c+3) = rte>>RTE.host // If we are about to go down, say that we are a terrible route to anywhere pbi>>PBI.pup.bytes↑(c+4) = gatewayGoingDown? maxHops+1, rte>>RTE.hops pbi>>PBI.pup.length = c+4 ] ] //---------------------------------------------------------------------------- and TMLookup(tm, sNet, dNet, findFree; numargs na) = valof //---------------------------------------------------------------------------- [ let key = sNet lshift 8 + dNet let iProbe = nil let increment = HHash(tm>>TM.logSize, key, lv iProbe) let probe = iProbe [ let tme = lv tm>>TM.TME↑probe if tme>>TME.sdNet eq key then resultis tme if tme>>TME.sdNet eq -1 then resultis na ge 4 & findFree? tme, 0 //fail probe = (probe+increment) & ((1 lshift tm>>TM.logSize)-1) ] repeatuntil probe eq iProbe resultis 0 //fail. Searched the whole table ] //---------------------------------------------------------------------------- and TMIncrement(sNet, dNet) be //---------------------------------------------------------------------------- // Looks up sNet,,dNet in the transit matrix hash table. // Creates an entry if not found then increments the count. [ let tme = TMLookup(gf>>GF.tm, sNet, dNet, true) if tme eq 0 then return // table full! if tme>>TME.sdNet eq -1 then // empty tme tme>>TME.sdNet = sNet lshift 8 + dNet DoubleIncrement(lv tme>>TME.count) ]