! 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.

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

%constinteger IP protocol type = 6

%include "INet:Common_Formats.Inc"
%include "INet:Utility.Inc"

%include "GDMR_E:2Meg.Inc"

!! %include "INet:Dump.Inc"

%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

%externalrecord(non peer info fm)%namespec sp

%ownrecord(mailbox fm)%name ether mailbox

%ownrecord(semaphore fm) TX semaphore = 0
%ownrecord(ether request fm) TX request = 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.
   %owninteger TX sequence = 0
   %record(ether request fm)%name r
   %integer target
      !! printstring("Slow ether outbound: ");  phex(addr(b))
      !! write(b_bytes, 1);  newline
      !! dump(byteinteger(addr(b_IP header)), b_bytes)
      target = b_IP peer & 255
      target = 0 %if target = 255;  ! Broadcast
      TX sequence = TX sequence + 1
      TX request_code = ether write
      TX request_tag = TX sequence
      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)
      sp_ether packets out = sp_ether packets out + 1
      sp_ether bytes out = sp_ether bytes out + b_bytes
      r == receive message(TX response)
      %if r_tag # TX sequence %start
         pdate
         printstring("INet slow ether: dud tag ")
         phex(r_tag);  space;  phex(TX sequence)
         newline
         sp_ether errors out = sp_ether errors out + 1
      %else %if r_status # ether success
         pdate
         printstring("INet slow ether: ")
         printstring(ether errors(r_status))
         newline
         sp_ether errors out = sp_ether errors out + 1
      %finish
      %if b_next queue == nil %start
         !! printstring("No next queue");  newline
         release buffer(b)
      %else
         b_stamp = msecs timestamp
         %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
%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)
         r == receive message(RX response)
         %if r_tag # RX sequence %start
            pdate
            printstring("INet slow ether: dud tag ")
            phex(r_tag);  space;  phex(RX sequence)
            newline
            sp_ether errors in = sp_ether errors in + 1
            release buffer(b)
         %else %if r_status # ether success
            pdate
            printstring("INet slow ether: ")
            printstring(ether errors(r_status))
            newline
            sp_ether errors in = sp_ether errors in + 1
            release buffer(b)
         %else
            b_bytes = r_bytes
            b_IP header == record(addr(b_data(32)))
            b_next queue == nil
            sp_ether packets in = sp_ether packets in + 1
            sp_ether bytes in = sp_ether 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
      %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
      %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 message(TX request, size of(TX request))
      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
      p == create process(inbound size, addr(start inbound), inbound priority, nil)
      !! printstring("INet slow ether handler started");  newline
      %return

start inbound:
      inbound process
%end

%end %of %file
