! INet process for interim Mouse (Moose), GDMR, Jan... 1988. Based on ! VAX/VMS version. %option "-NonStandard-Low-NoCheck-NoDiag-NoLine" ! This file contains some basic definitions and utility routines, together ! with the dispatcher loop at the end, but all the main components are ! linked in from separate files for convenience. Note: (a) there is a clock ! interrupt handler to deal with timestamp calculations and timeouts; (b) ! there is one common semaphore which is waited for by the main dispatch loop; ! (c) most of the subsidiary files are common with the VMS version, except that ! network-ordering is a no-op for 680x0 processors; (d) HMD's compiler is unable ! to cope with real programs using more than a small number of variables. %constinteger buffer pool size = 64 %externalinteger our address = 0 %externalinteger our network = 0 %constinteger ARP lives = 4 %include "INet:Common_formats.Inc" %include "INet:Utility.Inc" %systemroutinespec phex(%integer what) %systemintegerfnspec free store %externalintegerfnspec global heap get(%integer bytes) %externalrecord(semaphore fm) dispatch semaphore = 0 %externalinteger max TCP = 0, max UDP = 0 %externalrecord(non peer info fm)%name sp %externalrecord(TCB table fm)%name TCB table %externalrecord(UDP table fm)%name UDP table %externalrecord(peer table fm)%name peer table ! Queue headers %externalrecord(queue fm) ether outbound queue = 0 %externalrecord(queue fm) IP inbound queue = 0 %externalrecord(queue fm) IP outbound queue = 0 %externalrecord(queue fm) TCP inbound queue = 0 %externalrecord(queue fm) TCP outbound queue = 0 %externalrecord(queue fm) TCP first queue = 0 %externalrecord(queue fm) TCP sixth queue = 0 %externalrecord(queue fm) TCP packet delivered queue = 0 %externalrecord(queue fm) UDP inbound queue = 0 %externalrecord(queue fm) UDP outbound queue = 0 %externalrecord(queue fm) ICMP inbound queue = 0 %externalrecord(queue fm) ICMP outbound queue = 0 %externalrecord(queue fm) buffer lookaside list = 0 ! External module specs (and dummies) come here.... %externalinteger activity count = 0 %externalroutinespec start user interfaces(%integername a, b) %externalintegerspec slow ether address %externalroutinespec start slow ether %externalroutinespec slow ether outbound(%record(buffer fm)%name b) %externalroutinespec IP inbound(%record(buffer fm)%name b) %externalroutinespec IP outbound(%record(buffer fm)%name b) %externalroutinespec TCP enable(%integer i) %externalroutinespec TCP packet delivered(%record(buffer fm)%name b) %externalroutinespec TCP sixth(%record(buffer fm)%name b) %externalroutinespec TCP first(%record(buffer fm)%name b) %externalroutinespec TCP inbound(%record(buffer fm)%name b) %externalroutinespec TCP outbound(%record(buffer fm)%name b) %externalpredicatespec TCP retransmit timeouts %externalpredicatespec TCP pending acks %externalroutinespec TCB time wait timeouts %externalroutinespec UDP enable(%integer i) %externalroutinespec UDP inbound(%record(buffer fm)%name b) %externalroutinespec UDP outbound(%record(buffer fm)%name b) %externalroutinespec ICMP inbound(%record(buffer fm)%name b) %externalroutinespec ICMP outbound(%record(buffer fm)%name b) ! Clock handler %owninteger slow timer = 0 %owninteger fast timer = 0 %constinteger clock priority = 6 %externalinteger clock ticks = 0 %constinteger slow mask = 127; ! Deciseconds %routine start clock %ownrecord(interrupt handler fm) handler = 0 %label clock handler, C1, C2, C3 setup interrupt handler(handler, addr(clock handler)) add interrupt handler(handler, clock priority) !! printstring("INet module's clock handler inserted"); newline %return clock handler: *move.l clock ticks, D0 { Get current time *addq.l #1, D0 { Bump it *move.l D0, clock ticks { Write it back *clr.l D1 { Clear signal flag *tst.l activity count { Anything doing *bls C1 { Nothing fast, -> *move.l #1, fast timer { Tell dispatcher *move.l #1, D1 { Note we've to signal C1: *and.l #slow mask, D0 { Slow timer expired? *bne C2 { No, -> *move.l #1, slow timer { Tell dispatcher *move.l #1, D1 { Note we've to signal C2: *tst.l D1 { Signal required? *beq C3 { No, -> int signal semaphore(dispatch semaphore) C3: return from interrupt *move.l D0, D0; ! HMD-proof it %end ! Main program %begin %string(127) message, node name = "Unknown" %record(peer info fm)%name p %record(buffer fm)%name b %integer status, i, k open input(3, ":N"); select input(3) open output(3, ":T"); select output(3) !our address = INet name to address(node name) !%if our address = 0 %start ! message = "Undefined INet address for '" . node name . "'" ! tell network operator(message) ! %stop !%finish !message = "INet address for '" . node name . "' is " . %c ! INet address to S(our address) . " (" !split INet address(our address, i, our network, k) !%if k = '@' %start ! message = message . "unknown network type)" ! tell network operator(message) ! %stop !%finish !message = message . to string(k) . ")"; ! Append address-class !tell network operator(message) sp == named heap get(non peer size, non peer name) ! Initialise semaphores, queues setup semaphore(dispatch semaphore) setup queue(ether outbound queue) setup queue(IP inbound queue) setup queue(IP outbound queue) setup queue(TCP inbound queue) setup queue(TCP outbound queue) setup queue(TCP first queue) setup queue(TCP sixth queue) setup queue(TCP packet delivered queue) setup queue(UDP inbound queue) setup queue(UDP outbound queue) setup queue(ICMP inbound queue) setup queue(ICMP outbound queue) setup queue(buffer lookaside list) !! printstring("Dispatch semaphore at ") !! phex(addr(dispatch semaphore)); newline !! printstring("Free list at "); phex(addr(buffer lookaside list)) !! newline ! Start up the user interface start user interfaces(max TCP, max UDP) %if max TCP = 0 %start tell network operator("TCP units not configured") %else max TCP = max TCB table %if max TCP > max TCB table TCB table == named heap get(TCB size * max TCP, TCB table name) TCP enable(i) %for i = 1, 1, max TCP %finish %if max UDP = 0 %start tell network operator("UDP units not configured") %else max UDP = UDP table entries %if max UDP > UDP table entries UDP table == named heap get(UDP entry size * max UDP, UDP table name) UDP enable(i) %for i = 1, 1, max UDP %finish ! Set up buffer pool, etc %for i = 1, 1, buffer pool size %cycle b == record(global heap get(buffer size + 4)) release buffer(b) %repeat peer table == named heap get(peer table size, peer table name) ! Start devices, timers start clock start slow ether our address = 193 << 24 ! 208 << 16 ! 205 << 8 ! slow ether address our network = our address & 16_FFFFFF00 p == new peer info(our network); !<<<<<<<< Broadcast record <<<<<<<< {} printstring("Slow ether INet address: ") {} print inet address(our address); newline !setup gateways !start ICMP mailbox ! And off we go.... Scan the queues in turn, looking for buffers to ! dequeue. If we find any we call the appropriate service routine, then ! go back up to the top of the loop printstring("INet: "); write(free store, 0) printstring(" free"); newline %cycle b == dequeue buffer(ether outbound queue) %if b ## nil %start slow ether outbound(b) %continue %finish b == dequeue buffer(IP inbound queue) %if b ## nil %start IP inbound(b) %continue %finish b == dequeue buffer(IP outbound queue) %if b ## nil %start IP outbound(b) %continue %finish ! NB: TCP processing MUST come AFTER ether & IP to avoid ! race conditions with retransmit queues. Note also that TCP ! processing must take place in such an order as to ensire that ! later stages have a higer precedence than earlier stages -- this ! helps to avoid bogus "send-aheads". b == dequeue buffer(TCP packet delivered queue) %if b ## nil %start TCP packet delivered(b) %continue %finish b == dequeue buffer(TCP sixth queue) %if b ## nil %start TCP sixth(b) %continue %finish b == dequeue buffer(TCP first queue) %if b ## nil %start TCP first(b) %continue %finish b == dequeue buffer(TCP inbound queue) %if b ## nil %start TCP inbound(b) %continue %finish b == dequeue buffer(TCP outbound queue) %if b ## nil %start TCP outbound(b) %continue %finish %continue %if TCP pending acks %if fast timer # 0 %start !! printstring("Fast timer: "); write(activity count, 0); newline fast timer = 0 %continue %if TCP retransmit timeouts %finish b == dequeue buffer(UDP inbound queue) %if b ## nil %start UDP inbound(b) %continue %finish b == dequeue buffer(UDP outbound queue) %if b ## nil %start UDP outbound(b) %continue %finish b == dequeue buffer(ICMP inbound queue) %if b ## nil %start ICMP inbound(b) %continue %finish b == dequeue buffer(ICMP outbound queue) %if b ## nil %start ICMP outbound(b) %continue %finish %if slow timer # 0 %start !! printstring("Slow timer"); newline slow timer = 0 TCB time wait timeouts !? %continue %finish semaphore wait(dispatch semaphore) %repeat %end %of %program