-- File: PhoneAdoptionPup.mesa - last edit:
-- AOF                  4-Feb-88 19:38:14
-- HGM                 26-Oct-85 23:21:47
-- LSK                 28-Jun-85 14:56:18
-- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Buffer USING [Buffer, Type],
  CommHeap USING [zone],
  CommUtil USING [GetEthernetHostNumber],
  Driver USING [Device],
  Environment USING [bytesPerWord],
  Inline USING [LongCOPY],
  Mopcodes USING [zADD, zAND, zLI1, zLINB],
  NSBuffer USING [Body],
  PhoneAdoption USING [AdoptForNS],
  PhoneCreate USING [],
  PhoneNet USING [Initialize, Unsupported],
  Protocol1 USING [
    AddFamilyMember, Family,
    MatrixRecord, DecapsulatorProc, EncapsulatorProc],
  PupDefs USING [PupPackageMake],
  PupTypes USING [],
  PupRouterDefs USING [ContextObject],
  RS232C USING [ChannelHandle, CommParamObject, Create],
  RS232CEnvironment USING [],
  SptpOps USING [GetDevice, defaultMaxRS232CBytes, GetVersion],
  SptpProtocol USING [Encapsulation, EncapsulationObject, ProtocolVersion],
  System USING [NetworkNumber];

PhoneAdoptionPup: MONITOR 
  IMPORTS
    CommHeap, CommUtil, Inline, PhoneAdoption, PhoneNet,
    SptpOps, Protocol1, PupDefs, RS232C
  EXPORTS Buffer, PhoneCreate =
  BEGIN
  
  bpw: NATURAL = Environment.bytesPerWord;
  Device: PUBLIC  <<Buffer>> TYPE = Driver.Device;
    
  CreateSimplePhoneNet: PUBLIC PROC [
    lineNumber: CARDINAL, pupNet: CARDINAL, nsNet: System.NetworkNumber] =
    BEGIN
    parms: RS232C.CommParamObject ← [
      full, bitSynchronous, bps9600, directConn[]];
    chan: RS232C.ChannelHandle ← RS232C.Create[
      lineNumber, @parms, preemptAlways, preemptNever];
    PhoneNet.Initialize [
      lineNumber: lineNumber, channel: chan, commParams: @parms,
      negotiationMode: active, hardwareStatsAvailable: TRUE,
      ourEntityClass: internetworkRouter];

    PhoneAdoption.AdoptForNS [lineNumber<<, FALSE, System.nullNetworkNumber>>];
    AdoptForPup[lineNumber, pupNet];
    END;  --CreateSimplePhoneNet
  
  AdoptForPup: PROC [lineNumber: CARDINAL, pupNetNumber: CARDINAL] =
    BEGIN
    pupHostNumber: CARDINAL = CommUtil.GetEthernetHostNumber[];
    driver: Device = SptpOps.GetDevice[lineNumber];
    family: Protocol1.Family ← PupDefs.PupPackageMake[];
    matrix: Protocol1.MatrixRecord ← [  --AddFamilyMember copies fields
      family: family, context: ,
      encapsulator: EncapsulatePupPhonenet,
      decapsulator: DecapsulatePupPhonenet];
    matrix.context ← CommHeap.zone.NEW[PupRouterDefs.ContextObject ← [
      protocol: NIL, network: driver,
      pupNetNumber: pupNetNumber, pupHostNumber: pupHostNumber]];
    Protocol1.AddFamilyMember[driver, @matrix];
    matrix.family.stateChanged[driver, matrix.context, add];
    END;
    
  --**************** Encapsulation and decapsulation **************
  
  DecapsulatePupPhonenet: 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.
    These calls to SptpOps.Get* are expensive. It would be nice to be able
    to get to some state object more cheaply to determine whether we are
    connected to an SIU or not.
    >>
    size: NATURAL;
    body: NSBuffer.Body; 
    device: Device = b.fo.network;  --get pointer to network
    <<version: SptpProtocol.ProtocolVersion = SptpOps.GetVersion[device];>>

    WITH e: LOOPHOLE[b.linkLayer.blockPointer, SptpProtocol.Encapsulation]
      SELECT FROM pup => size ← SIZE[pup SptpProtocol.EncapsulationObject];
      ENDCASE => RETURN[vagrant];  --go away

    body ← LOOPHOLE[b.linkLayer.blockPointer + size];  --that's fair
    b.highLayer ← [LOOPHOLE[body], 0, body.pktLength];  --from the packet
    b.linkLayer.stopIndexPlusOne ← (bpw * size);  --'size' now bytes
    RETURN[pup];  --that was easy
    END;

  EncapsulatePupPhonenet: Protocol1.EncapsulatorProc =
    BEGIN
    <<
    Coming in here we know that the packet is an NS packet and that
    b.highLayer.blockPointer points to the NSBuffer.BodyBody. 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. It first blaps
    in a non-descriminated record which is several bytes longer than an
    ns SptpProtocol.EncapsulationObject. Then it goes back and fills in the
    particulars. Regettably by then the first 'n' bytes of the original
    packet are destroyed. 
    >>
    size: NATURAL;  --this variable is overloaded
    link: LONG POINTER;  --computed to point to data link fields
    encapsulation: SptpProtocol.EncapsulationObject;  --this is our local copy
    device: Device = b.fo.network;  --get pointer to network
    body: NSBuffer.Body = LOOPHOLE[b.highLayer.blockPointer];
    of: NATURAL = body.pktLength / SptpOps.defaultMaxRS232CBytes;
    version: SptpProtocol.ProtocolVersion = SptpOps.GetVersion[device];

    SELECT version FROM
      version4 =>
        BEGIN
        encapsulation ← [pup[LTA: FALSE, more: (of # 0), fragment: [0, of]]];
	size ← SIZE[pup SptpProtocol.EncapsulationObject];
	END;
      version3 =>
        BEGIN
        IF (of # 0) THEN ERROR PhoneNet.Unsupported;
	encapsulation ← [pup[LTA: FALSE, more: FALSE, fragment: [0, 0]]];
	size ← SIZE[pup SptpProtocol.EncapsulationObject];
	END;
      ENDCASE => ERROR PhoneNet.Unsupported; 

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

  Roundup: PROC[NATURAL] RETURNS[NATURAL] = MACHINE CODE {
    Mopcodes.zLI1; Mopcodes.zADD; Mopcodes.zLINB, 376B; Mopcodes.zAND};
    
    
  minBytesPerPup: CARDINAL = 22;
    
  END..