!iso4
! Uni-process implementation of ISO-TL

%include "inc:util.imp"
%include "ether:iso4.inc"
%include "ether:iso.inc"
%include "ether:iso4sum"

%recordformat list f (%record(listf)%name next,prev,%record(*)%name rec)
%ownrecord(listf)%name tc list == nil
%owninteger clock phase=0

%recordformat i tc f (%record(tcf)userpart,
   %half lref,rref,%integer state,nextin,inlimit,nextout,outlimit,
   %record(listf)%name inpend,outpend)

%constinteger max tc = 20
%ownrecord(i tc f)%namearray tc refs(1:maxtc) == nil(*)

%constinteger-
 clock bit    =   1, {clock phase indicator
 cr sent      =   2, {TCRQ received from user, CR TPDU sent
 cr received  =   4, {CR TPDU received
 cr indicated =   8, {TCI sent to user
 ca sent      =  16, {TCRE received from user, CA TPDU sent
 ca received  =  32, {CA TPDU received
 ca confirmed =  64, {TCC sent to user
 dr sent      = 128, {TDR received from user, DR TPDU sent
 dr received  = 256, {DR TPDU received
 dr indicated = 512  {TDI sent to user

%externalstring(*)%map heapstring(%string(255)s)
%string(*)%name t
  %result == nil %if s=""
  t == string(heapget(length(s)+1))
  t = s
  %result == t
%end

%halffn new tc ref
%integer i
  %for i = 1,1,maxtc %cycle
    %result = i %if tcrefs(i)==nil
  %repeat
  %signal 3,4,,"Too many transport connections"
%end

%externalrecord(tc f)%map T ALLOCATE TC REF (%string(63) LSAP, RSAP)
! Returns a reference to a (new) connection record.
%record(itcf)%name tc
%record(listf)%name cell
%half lref
  lref = new tc ref
  tc == new(tc)
  tc = 0
  tc_lref = lref
  tc_userpart_lsap == heapstring(lsap)
  tc_userpart_rsap == heapstring(rsap)
  cell == new(cell)
  cell_rec == tc
  cell_prev == nil
  cell_next == tc list
  tc list == cell
  %result == tc_userpart
%end

%record(listf)%map validate tc(%record(tcf)%name tc)
%record(listf)%name c
  c == tc list
  %cycle
    %signal 3,4,,"Invalid TC reference supplied" %if c==nil
    %result == c %if c_rec==tc
    c == c_next
  %repeat
%end

%routine move(%integer bytes,%bytename from,to)
%label nothing
  *subq.w #1,bytes
  *bmi nothing
loop: *move.b (a0)+,(a1)+
      *dbra d0,loop
nothing:
%end
 
%routine add parm(%byte code,%record(parmf)%name p,%record(tpduf)%name t)
%bytename source,dest
%integer size
  source == p_code; source = code
  dest == t_byte(t_li+2)
  size = length(p_string)+2
  move(size,source,dest)
  t_li = t_li+size
%end

%externalroutine T CONNECT REQUEST -
   (%record(tc f)%name REF, %string(32) DATA)
! Attempt to make a connection to the remote entity indicated by REF_RSAP,
! with the QOS parameters in REF, and with optional DATA as provided.
%record(itcf)%name tc
%record(tpduf)%name tpdu
%record(parmf)parm
%integer sumpos
  tc == validate tc(ref)_rec
  %signal 3,4,,"TC already connected" %unless tc_state=0
  tc refs(tc_lref) == tc
  tpdu == new(tpdu)
  tpdu_li = fhp cr
  tpdu_code = cr tpdu
  tpdu_sref = tc_lref
  tpdu_classopt = class4+extendedformats
  %unless tc_userpart_lsap==nil %start
    parm_string = tc_userpart_lsap; add parm(pc cgid,parm,tpdu)
  %finish
  %unless tc_userpart_rsap==nil %start
    parm_string = tc_userpart_rsap; add parm(pc cdid,parm,tpdu)
  %finish
  parm_byte(0) = 1; parm_byte(1) = lmt; add parm(pc size,parm,tpdu)
  parm_byte(0) = 1; parm_byte(1) = 1; add parm(pc ver,parm,tpdu)
  parm_byte(0) = 2; add parm(pc sum,parm,tpdu); sumpos = tpdu_li
  move(length(data),charno(data,1),tpdu_byte(tpdu_li+1)) %unless data=""
  generate sum(tpdu_li,tpdu_li+1+length(data),sumpos)
  tc_state = tc_state!crsent
{now schedule the TPDU for transmission}
%end

%externalrecord(tc f)%map T CONNECT INDICATED -
   (%string(63) LSAP, %integer WAIT)
! If some other end has attempted to establish a connection with the
! caller, identified as LSAP, a reference to a connection record is
! returned.  If not, NIL is returned if WAIT=0; otherwise the called
! is suspended.
%end

%externalroutine T CONNECT RESPONSE -
   (%record(tc f)%name REF, %string(32) DATA)
! Either this or T DISCONNECT REQUEST should be called by someone who
! has received a non-NIL result from T CONNECT INDICATED.
%end

%externalroutine T DISCONNECT REQUEST -
   (%record(tc f)%name REF, %string(43) REASON, %string(64) DATA)
! Shut down the connection identified by REF, optionally supplying
! an explanatory reason and data.
%end

%externalintegerfn T CONNECTED -
   (%record(tc f)%name REF, %string(*)%name REASON, DATA, %integer WAIT)
! If the connection is still being negotiated (the other end has not
! yet responded), then the result is 0 (if WAIT=0, otherwise caller
! is suspended) and REASON and DATA are unaffected.
! If the connection has been established, the result is >0, and DATA
! receives the message supplied at the other end via T CONNECT RESPONSE.
! Otherwise the connection has been shut down, the result is <0, and DATA
! and REASON receive information provided by T DISCONNECT REQUEST.
%end

%externalroutine T EXPEDITED DATA REQUEST -
   (%record(tc f)%name REF, %string(16) DATA)
! Sends a quickie (if enabled by negotiation).
%end

%externalroutine T DATA REQUEST-
   (%record(tc f)%name REF, %name WHERE, %integer SIZE, %byte EOF)
! Passes a TIDU across the interface.  SIZE bytes of data, in store at
! WHERE, are transmitted.  If EOF#0, this constitutes the last TIDU
! making up a TSDU.
%end

%externalintegerfn T DATA INDICATED (%record(tc f)%name REF, %integer WAIT)
! If no TSDU has arrived on the connection, the result is 0 (unless
! WAIT#0, in which case the caller is suspended).
! If a DATA unit is available, the result is >0.
! If an EXPEDITED DATA unit is available, or the connection has been
! broken, the result is <0.
%end

%externalroutine T ACCEPT DATA (%record(tc f)%name REF, -
   %name WHERE, %integername SIZE, %bytename EOF, %integer WAIT)
! A pending data unit is copied into store at WHERE.  SIZE on entry
! indicates the maximum size of the TIDU the caller is prepared to accept.
! SIZE will be set to the number of bytes actually copied.  This will
! be negative if the connection is broken or an EXPEDITED DATA unit
! is pending, or no data is available and WAIT=0.  EOF is set if this
! was the last TIDU of a TSDU.
%end

%externalroutine T ACCEPT EXPEDITED DATA -
   (%record(tc f)%name REF, %string(16)%name DATA)
! Should only be called when an expedited data unit is known to be there.
%end
