! Slow ether module for (Moose) INet proceess, GDMR, Jan 1988

! This module contains an external procedure which is called by the main
! dispatcher to send a buffer out to the ether, and an autonomous process
! which takes packets from the ether and fills in the relevant fields in the
! buffer before putting it on the inbound IP queue.

%option "-Nonstandard-NoCheck-NoDiag-NoLine"

%constinteger inbound priority = 7
%constinteger inbound size = 10240
%constinteger out done priority = 7
%constinteger out done size = 10240

%constinteger IP protocol type = 6

%include "INet:Formats.Inc"
%include "INet:Utility.Inc"
%include "INet:Stats.Inc"
%include "INet:Lights.Inc"

%include "GDMR_E:2Meg.Inc"

!! %include "INet:Dump.Inc"

%externalrecord(INet statistics fm)%spec stats

%externalpredicatespec FS lookup(%string(31) what, %integername value)

%systemroutinespec phex(%integer x)

%externalrecord(semaphore fm)%spec dispatch semaphore
%externalrecord(queue fm)%spec IP inbound queue

%externalinteger slow ether address = 0

%externalintegerspec slow IP address
%externalintegerspec slow network

%externalroutinespec add local route(%integer network, metric, %integer via)

!%externalrecord(non peer info fm)%namespec sp

%ownrecord(mailbox fm)%name ether mailbox

%ownrecord(semaphore fm) TX semaphore = 0
%ownrecord(mailbox fm) TX response = 0

%ownrecord(semaphore fm) RX semaphore = 0
%ownrecord(ether request fm) RX request = 0
%ownrecord(mailbox fm) RX response = 0

%externalroutine slow ether outbound(%record(buffer fm)%name b)
   ! Send the specified buffer on its way as protocol type 6.  Note that
   ! ether addresses are formed from IP addresses by taking the low-order
   ! 8 bits worth -- assuming class-C addresses, this would be the "address-
   ! within-network" part.
   %record(ether request fm)%name TX request
   %integer target
      !! printstring("Slow ether outbound: ");  phex(addr(b))
      !! write(b_bytes, 1);  space;  print INet address(b_IP peer)
      !! space;  print INet address(b_IP target);  newline
      !! dump(byteinteger(addr(b_IP header)), b_bytes)
!L!   lights or B(slow ether light)
      target = b_IP target & 255
      target = 0 %if target = 255;  ! Broadcast
      TX request == record(addr(b_message(0)))
      setup message(TX request, size of(TX request))
      TX request_code = ether write
      TX request_tag = addr(b)
      TX request_ra = target
      TX request_type = IP protocol type
      TX request_buffer == byteinteger(addr(b_IP header))
      TX request_bytes = b_bytes
      send message(TX request, ether mailbox, TX response)
      ! Response will be handled by autonomous process below...
%end

%routine outbound done
   %record(ether request fm)%name r
   %record(buffer fm)%name b
      open input(2, ":N");  select input(2)
      open output(2, ":T");  select output(2)
      %cycle
         r == receive message(TX response)
         %if r_status # ether success %start
            pdate
            printstring("INet slow ether: ")
            printstring(ether errors(r_status))
            newline
            stats_slow errors out = stats_slow errors out + 1
         %finish
         ! Finally drop/enqueue the packet.  It will be retransmitted
         ! by the higher layers if required....
         b == record(r_tag)
         stats_slow packets out = stats_slow packets out + 1
         stats_slow bytes out = stats_slow bytes out + b_bytes
         %if addr(b_IP header) # addr(r_buffer) %start
            printstring("Dubious buffer address: ");  phex(addr(b))
            space;  phex(addr(b_IP header));  space
            phex(addr(r_buffer));  newline
         %finish
         %if b_next queue == nil %start
            !! printstring("No next queue");  newline
            release buffer(b)
         %else
            %if b_flags & requeue flag # 0 %start
               !! printstring("Requeue on ");  phex(addr(b_next queue));  newline
               requeue(b, b_next queue)
            %else
               !! printstring("Enqueue on ");  phex(addr(b_next queue));  newline
               enqueue(b, b_next queue)
            %finish
         %finish
!L!      lights and B(\ slow ether light)
      %repeat
%end

%routine inbound process
   %owninteger RX sequence = 0
   %record(buffer fm)%name b
   %record(ether request fm)%name r
      open input(2, ":N");  select input(2)
      open output(2, ":T");  select output(2)
      !! printstring("Slow inbound handler started");  newline
      %cycle
         b == claim buffer
         %if b == nil %start
            printstring("No buffers??");  newline
            %stop
         %finish
         !! printstring("Inbound buffer at ");  phex(addr(b));  newline
         RX sequence = RX sequence + 1
         RX request_code = ether read
         RX request_tag = RX sequence
         RX request_type = IP protocol type
         RX request_buffer == b_data(32)
         send message(RX request, ether mailbox, RX response)
         !! printstring("Read queued, buffer at ");  phex(addr(b));  newline
         r == receive message(RX response)
!L!      lights or A(slow ether light)
         %if r_tag # RX sequence %start
            pdate
            printstring("INet slow ether: dud tag ")
            phex(r_tag);  space;  phex(RX sequence)
            newline
            stats_slow errors in = stats_slow errors in + 1
            release buffer(b)
         %else %if r_status # ether success
            pdate
            printstring("INet slow ether: ")
            printstring(ether errors(r_status))
            newline
            stats_slow errors in = stats_slow errors in + 1
            release buffer(b)
         %else
            b_bytes = r_bytes
            b_IP header == record(addr(b_data(32)))
            b_next queue == nil
            b_flags = broadcast flag %if r_ra = 0
            b_interface = 1
            stats_slow packets in = stats_slow packets in + 1
            stats_slow bytes in = stats_slow bytes in + b_bytes
            !! printstring("Received ");  write(b_bytes, 0)
            !! printstring(" into ");  phex(addr(b));  newline
            !! dump(byteinteger(addr(b_IP header)), b_bytes)
            enqueue(b, IP inbound queue)
            signal semaphore(dispatch semaphore)
         %finish
!L!      lights and A(\ slow ether light)
      %repeat
%end

%externalroutine start slow ether
   ! Set up mailboxes, etc, register ourselves as protocol 6, and start
   ! the receiver process.
   %record(process fm)%name p
   %record(ether request fm)%name r
   %integer x
   %label start inbound, start out done
      %if FS lookup(ether mailbox name, x) %start
         ether mailbox == record(x)
      %else
         printstring("No slow ether mailbox??");  newline
         %stop
      %finish
      setup semaphore(TX semaphore)
      setup mailbox(TX response, TX semaphore)
      setup semaphore(RX semaphore)
      setup mailbox(RX response, RX semaphore)
      setup message(RX request, size of(RX request))
      RX request_code = ether register
      RX request_type = IP protocol type
      send message(RX request, ether mailbox, RX response)
      r == receive message(RX response)
      %if r_status # ether success %start
         printstring("Register: ");  printstring(ether errors(r_status))
         newline
         %stop
      %finish
      RX request_code = ether station address
      send message(RX request, ether mailbox, RX response)
      r == receive message(RX response)
      %if r_status # ether success %start
         printstring("Enquire address: ");  printstring(ether errors(r_status))
         newline
         %stop
      %finish
      slow ether address = r_context
      slow IP address = 193 << 24 ! 208 << 16 ! 205 << 8 ! slow ether address
      slow network = slow IP address & 16_FFFFFF00
      add local route(slow IP address, 1, 1)
      {} printstring("Slow ether IP address is ")
      {} print INet address(slow IP address);  newline
      p == create process(inbound size, addr(start inbound), inbound priority, nil)
      p == create process(out done size, addr(start out done), out done priority, nil)
      !! printstring("INet slow ether handler started");  newline
      %return

start inbound:
      inbound process
start out done:
      outbound done
%end

%end %of %file
