-- File: ArpaSptpImpl.mesa - last edit:
-- AOF                  1-Mar-88 13:22:48
-- JAV                 30-Nov-87 12:08:38

-- Copyright (C) 1987, 1988 by Xerox Corporation. All rights reserved.


DIRECTORY
  ArpaBuffer USING [Body],
  ArpaInit USING [GetArpaInitInfo],
  ArpaPort USING [minIPHeaderBytes],
  ArpaPortInternal USING [BuildMasks],
  ArpaRouter USING [InternetAddress, unknownInternetAddress],
  ArpaRoutingTable USING [ContextObject, NetworkContext],
  ArpaSptp USING [],
  CommHeap USING [zone],
  Driver USING [Device],
  Environment USING [bytesPerWord],
  Inline USING [LongCOPY],
  Protocol1 USING [AddFamilyMember, DecapsulatorProc, EncapsulatorProc, Family,
    GetContext, GetFamilyUnit, MatrixRecord, RemoveFamilyMember],
  SptpOps USING [defaultMaxRS232CBytes],
  SptpProtocol USING [Encapsulation, EncapsulationObject];

ArpaSptpImpl: MONITOR 
  IMPORTS ArpaInit, ArpaPortInternal, ArpaRouter, CommHeap, Inline, Protocol1
  EXPORTS ArpaSptp =
  
  BEGIN
  bpw: NATURAL = Environment.bytesPerWord;
  
  AdoptForArpa: PUBLIC <<ArpaSptp>> PROC[
    host: ArpaRouter.InternetAddress, adoptee: Driver.Device] =
    BEGIN
      mySubnetMask: ArpaRouter.InternetAddress;
    family: Protocol1.Family ← Protocol1.GetFamilyUnit[arpa];
    matrix: Protocol1.MatrixRecord ← [
      family: family, context: ,
      encapsulator: ArpaEncapsulation, decapsulator: ArpaDecapsulation];
      BEGIN
	OPEN c: LOOPHOLE[matrix.context, ArpaRoutingTable.NetworkContext];
	matrix.context ← CommHeap.zone.NEW[ArpaRoutingTable.ContextObject];
	c.network ← adoptee;
	c.stats ← NIL;
	c.protocol ← NIL;
	c.net ← host;
	c.host ← host;  -- this is the address of the host for this net.
        [c.hostMask, c.netMask] ← ArpaPortInternal.BuildMasks[c.host];
	IF (mySubnetMask ← ArpaInit.GetArpaInitInfo[].subnetMask) #
	  ArpaRouter.unknownInternetAddress THEN
	    c.netMask ← mySubnetMask;  --are subnets in use?
	Protocol1.AddFamilyMember[LOOPHOLE[adoptee], @matrix];
      END;
    END;  --AdoptForArpa
    
    
  DisownFromArpa: PUBLIC <<ArpaSptp>> PROC [adoptee: Driver.Device] =
    BEGIN
    context: ArpaRoutingTable.NetworkContext ←
      Protocol1.GetContext[LOOPHOLE[adoptee], arpa];
    family: Protocol1.Family ← Protocol1.GetFamilyUnit[arpa];
    Protocol1.RemoveFamilyMember[LOOPHOLE[adoptee], family];
    CommHeap.zone.FREE[@context];
    END;  --DisownFromArpa
    
  --**************** Encapsulation and decapsulation **************
  
  ArpaDecapsulation: PUBLIC Protocol1.DecapsulatorProc =
    --PROCEDURE [b: Buffer.Buffer] RETURNS [type: Buffer.Type]
    BEGIN
    <<
    When coming in here we are assured that b.linkLayer.blockPointer
    points to the beginning of the physical frame. That frame starts with
    the sptp's encapsulation record. From that information we should be
    able to compute the address of the data portion.
    >>
    size: NATURAL;
    body: ArpaBuffer.Body; 
    device: Driver.Device = LOOPHOLE[b.fo.network];  --get pointer to network

    WITH e: LOOPHOLE[b.linkLayer.blockPointer, SptpProtocol.Encapsulation] SELECT FROM
      arpa => NULL;  --data packet for arpa customer - get it up to network layer
      ENDCASE => RETURN[vagrant];
    size ← SIZE[arpa SptpProtocol.EncapsulationObject];  --in words
    body ← LOOPHOLE[b.linkLayer.blockPointer + size];  --that's fair
    b.highLayer ← [LOOPHOLE[body], 0, body.ipHeader.length];
    b.linkLayer.stopIndexPlusOne ← size ← (bpw * size);  --in bytes
    SELECT TRUE FROM
      (b.fo.driver.length < size --in bytes--) => RETURN[orphan];  --busted
      (body.ipHeader.length < ArpaPort.minIPHeaderBytes) => RETURN[orphan];  --busted
      ENDCASE => RETURN[arpa];  --life is sooooo good
    END;  --ArpaDecapsulation

  ArpaEncapsulation: PUBLIC Protocol1.EncapsulatorProc =
    BEGIN
    <<
    Coming in here we know that the packet is an Arpa packet and that
    b.highLayer.blockPointer points to the ArpaBuffer.Body. We need to back
    off some number of bytes from that point and stick in the proper encap-
    sulation.
    NB: The Inline.LongCOPYs are here because the compiler generates somewhat
    unuseful code if you use a more direct approach to things.
    >>
    size: NATURAL;
    link: LONG POINTER;
    encapsulation: SptpProtocol.EncapsulationObject;
    body: ArpaBuffer.Body = LOOPHOLE[b.highLayer.blockPointer];
    of: NATURAL = body.ipHeader.length / SptpOps.defaultMaxRS232CBytes;

    encapsulation ← [arpa[LTA: FALSE, more: FALSE, fragment: [1, of.SUCC]]];
    size ← SIZE[arpa SptpProtocol.EncapsulationObject];  --in words

    <<THIS DOESN'T SUPPORT MULTIPLE VERSIONS OF THE SPTP PROTOCOL>>

    link ← body - size;  --this is backoff to beginning of link layer
    Inline.LongCOPY[to: link, from: @encapsulation, nwords: size];
    size ← bpw * size;  --in bytes
    b.linkLayer ← [link, 0, size];  --set the link layer values
    b.fo.driver.length ← body.ipHeader.length + size;  --and frame is sum of both

    END;  --ArpaEncapsulation
    
    
    
  END..