home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / b / krtpak.mac < prev    next >
Text File  |  2020-01-01  |  47KB  |  1,330 lines

  1.     .title    KRTPAK    Packet driver
  2.     .ident    "V03.63"
  3.  
  4. ; /63/    27-Sep-97  Billy Youdelman  V03.63
  5. ;
  6. ;    make .TOGO = 16, fixing a (harmless) typo (was 26)..
  7. ;    dump ^A = restart a packet for SET CONTROL UNPREFIX 1 operation
  8. ;    BUFFIL back to root (KRTPAK), for speed and room now available
  9. ;    ERROR: now sends error packet when link is open and xfr in progress
  10. ;    modify BUFFIL to do BUFPAK too, for repeated char encoding
  11.  
  12. ; /62/    27-Jul-93  Billy Youdelman  V03.62
  13. ;
  14. ;    move erbfsiz to KRTMAC
  15. ;    patch PRINTM to also write to a logfile, when same is in use
  16. ;    add logfile error handler and provide for logfile errors
  17. ;    write error messages to logfile
  18. ;    include file spec in getnxt error messages
  19. ;    add individual packet exchange duration timer, for debugging
  20. ;    make BUFFIL limit test max-0 (was max-4), allows bigger packets
  21. ;    don't log bogus data for timout
  22. ;    make ERROR send an error packet, use PRINTM elsewhere
  23. ;    don't modify SET time-out value
  24. ;    add/enforce SET SEND PACKET-LEN limit
  25. ;    move bufpak to KRTSER, no one else uses it
  26. ;    move buffil to KRTSEN, ditto..
  27. ;    move bufemp to KRTREC
  28. ;    add passed buffer length to rpack$
  29.  
  30. ; /BBS/     1-Dec-91  Billy Youdelman  V03.61
  31. ;
  32. ;    added lun.ld == 12 for TSX logical disk support
  33. ;    added lun.at == 5 for file attributes support
  34. ;    prefixing error messages with the prompt string moved to KRTERR
  35. ;    waitsoh - ^Z abort changed to ^C abort, thus not killing the pgm
  36. ;
  37. ;    spack$ packet length test fixed to determine the true length of
  38. ;    a packet near or equal to 94 bytes when long packets are used.
  39. ;    it was possible to generate a "normal" packet with an out-of-
  40. ;    range LENGTH character (using all eight bits) when reaching the
  41. ;    the EOF produced a last packet in a long packet series close to
  42. ;    94 bytes, as the routine filling the packet data input buffer
  43. ;    is still looking for enough to make a long packet, with no
  44. ;    consideration for the added SEQ and TYP bytes nor the checksum
  45. ;    size (up to three more bytes with CRC block checking)..
  46. ;
  47. ;    rpakst patched to hose link device whenever the "T" (time-out)
  48. ;    packet count is incremented, or when a NAK xxx NAK series
  49. ;    (indicating resonating packets) occurs.  this is very helpful
  50. ;    when telephone line noise crashes/hangs the handler..
  51. ;
  52. ;    space padding between elements of an error message moved from
  53. ;    error: to the err msgs themselves as printm doesn't do it, and
  54. ;    it's too confusing otherwise..
  55. ;
  56. ;    patched to compensate for crossing midnight, as long as
  57. ;    there's less than 24 hours between calls to it, thus 32-bit
  58. ;    time data from incsta are thought to be sufficient here
  59. ;    note: the display routine in krtsho limits max to 18.2 hours..
  60. ;
  61. ;    patched bufemp to not output the lead-in char to TT under TSX
  62. ;
  63. ;    moved RPACK debug stuff to rawio: as when it was in rpakrd: it
  64. ;    missed the SOH, which is handled by waitsoh: (both call rawio)..
  65. ;    also cleaned up display at the EOL and added display of TIMOUTs
  66. ;
  67. ;    fixed non-init'd repeat count reg bug in bufunpack
  68.  
  69. ;    Brian Nelson    30-Nov-83  10:20:09
  70. ;    13-Oct-84  14:01:32  BDN    moved SENDSW and RECSW out
  71. ;
  72. ;    Change Software, Toledo, Ohio
  73. ;    University of Toledo, Toledo, Ohio
  74.  
  75.  
  76. ;                 PACKET FORMAT
  77. ;
  78. ; The KERMIT protocol is built around exchange of packets of this format:
  79. ;
  80. ;    +------+-----------+-----------+------+- ~ ---- ~ -+-------+-----+
  81. ;    | MARK | char(LEN) | char(SEQ) | TYPE |    DATA    | CHECK | EOL |
  82. ;    +------+-----------+-----------+------+- ~ ---- ~ -+-------+-----+
  83. ;
  84. ; where all fields consist of ASCII characters.  The fields are:
  85. ;
  86. ; MARK  The synchronization character that marks the beginning of the packet.
  87. ;      This is normally ^A, but may be redefined.
  88. ;
  89. ; LEN  The  number  of  ASCII  characters  within  the packet that follow this
  90. ;      field, in other words the packet length minus two.  Since  this  number
  91. ;      is  transformed  to  a single character via the char() function, packet
  92. ;      character  counts  of  0. to 94. are permitted, and  96. is the maximum
  93. ;      total packet length.  The length doesn't include end-of-line or padding
  94. ;      characters, which are outside  the  packet  and  are  strictly  for the
  95. ;      benefit of the operating system,  but  it  does include the block check
  96. ;      characters.
  97. ;
  98. ; SEQ  The packet sequence number modulo 64., ranging from 0. to 63.  Sequence
  99. ;      numbers "wrap around" to 0. after each group of 64. packets.
  100. ;
  101. ; TYPE  The packet type, a single ASCII character.  The following packet types
  102. ;       are used in the Kermit protocol -
  103. ;
  104. ;  A = Attributes                     K = Kermit (remote) command
  105. ;  B = Break transmission (EOT)       N = Negative acknowledgment (NAK)
  106. ;  C = Host (remote) command          R = Receive file init
  107. ;  D = Data packet                    S = Send file init
  108. ;  E = Error                          T = Time out (internal)
  109. ;  F = File header (name)             X = Extended reply
  110. ;  G = Generic (remote) command       Y = Acknowledgment (ACK)
  111. ;  I = Server init                    Z = End of file (EOF)
  112. ;
  113. ; DATA  The contents of the packet,  if any contents are required in the given
  114. ;      type of packet, interpreted according to  the  packet  type.    Control
  115. ;      characters  are  preceded  by a special prefix character, normally "#",
  116. ;      and "uncontrollified" via ctl().  A prefixed sequence may not be broken
  117. ;      across packets.  Logical records in printable files are delimited  with
  118. ;      CR/LFs, suitably prefixed (e.g. "#M#J").  Any prefix characters are in-
  119. ;      cluded in the count.  Optional encoding for  8-bit  data  and  repeated
  120. ;      characters is also available.
  121. ;
  122. ; CHECK  A block check on characters in the packet between,  but not including
  123. ;      ing, the mark and the block check itself.  The check for each packet is
  124. ;      computed by both hosts,  and  must agree if a packet is to be accepted.
  125. ;      A single-character arithmetic checksum is the normal and required block
  126. ;      check.   Only  six  bits  of the arithmetic sum are included.  In order
  127. ;      that all the bits of each data character contribute to  this  quantity,
  128. ;      bits  6  and  7  of the final value are added to the quantity formed by
  129. ;      bits 0-5.  Thus if s is the arithmetic sum  of  the  ASCII  characters,
  130. ;      then
  131. ;
  132. ;        check = char((s + ((s & 192.)/64.)) & 63.)
  133. ;
  134. ;      This  is  the  default  block check, and all Kermits must be capable of
  135. ;      performing it.  Other optional block check types are also defined.  The
  136. ;      block check  is  based  on  the  ASCII  values of the characters in the
  137. ;      packet.    Non-ASCII  systems must translate to ASCII before performing
  138. ;      the block check calculation.
  139. ;
  140. ; EOL  The End Of Line character, normally a carriage return, marks the end of
  141. ;      the packet.  This particular implementation (Kermit-11) uses the packet
  142. ;      length and ignores the EOL char other than displaying it when debugging
  143. ;      to the terminal.
  144.  
  145.  
  146.     .include "IN:KRTMAC.MAC"
  147.     .iif ndf  KRTINC  .error    <; .include for IN:KRTMAC.MAC failed>
  148.     .include "IN:KRTDEF.MAC"
  149.     .iif ndf  MSG$DA  .error    <; .include for IN:KRTDEF.MAC failed>
  150.  
  151.     .mcall    .CLOSE            ; /63/ drop .GTIM, ,.PURGE
  152.  
  153.  
  154.     .sbttl    Misc defaults
  155.  
  156.     BADCHK    ==    377        ; pseudo packet type for bad checksum
  157.     DEFCHK    ==     '1        ; default block-check-type
  158.     TIMOUT    ==   'T&137        ; pseudo packet type for time-out
  159.  
  160.  
  161.     .sbttl    Local and global read-only data
  162.  
  163.     .psect    $pdata    ; /62/ MUST be non-swapping, in root (SJ) or APR1 (XM)
  164. aspace::.byte    40 ,0    ; /62/ consolidated all this here..
  165. null::    .byte     0 ,0
  166. e$pari:    .asciz    ", parity is possibly being introduced"
  167. e$retr:    .asciz    "Retry limit reached"
  168. e$sync:    .asciz    "Packet serial numbers are out of sync"
  169. pak.01:    .asciz    "Kermit: "
  170. pak.02:    .asciz    "<<< RPACK - "
  171. pak.03:    .asciz    "<TIMOUT>"
  172. pak.04:    .asciz    "BAD Checksum: RCV,CALC = "
  173. pak.05:    .asciz    "<SOH>"
  174. pak.06:    .ascii    "<EOL>"
  175. pak.07:    .asciz    <cr><lf>
  176. pak.08:    .asciz    ">>> SPACK - "
  177.     .even
  178.  
  179.  
  180.     .psect    $code
  181.     .sbttl    Read incoming packet
  182.  
  183. ;    R P A C K $
  184. ;
  185. ;    input:      (r5)    = packet buffer address
  186. ;         4(r5)    = packet buffer length
  187. ;    output:     2(r5)    = 3 word data structure returns length, number, type
  188.  
  189.     O$LEN    =  0        ; offset for returned packet length
  190.     O$SEQ    =  2        ; packet number
  191.     O$TYP    =  4        ; packet type
  192.  
  193.     ; /62/    local data allocated on the stack, offsets from r4
  194.     .TYP    =  0        ; packet type
  195.     .CCHECK    =  2        ; computed checksum
  196.     .RCHECK    =  4        ; received checksum
  197.     .LEN    =  6        ; received packet length
  198.     .TIMEO    = 10        ; read time-out
  199.     .SEQ    = 12        ; received packet number
  200.     .SIZE    = 14        ; current size of data portion
  201.     .TOGO    = 16        ; /63/ loop count control for data portion
  202.     .HDTYPE    = 20        ; /62/ header type
  203.     .CBUFF    = 22        ; /62/ checksum buffer address
  204.     .LSIZE    = 24        ; total size of the above local data
  205.  
  206. ;    internal register usage:
  207. ;    r0    = scratch register
  208. ;    r1    = current character just read from remote
  209. ;    r2    = pointer to packet buffer
  210. ;    r3    = pointer to temp buffer on the stack containing the packet
  211. ;          less the SOH and the checksum, for computing checksum after
  212. ;          the packet has been read
  213. ;    r4    = pointer to local data on stack, as defined above
  214. ;    r5    = pointer to argument list
  215.  
  216. rpack$::call    dcdtst            ; /62/ check DCD, report any change..
  217.     save    <r1,r2,r3,r4>
  218.     clr    recbit            ; /43/ clear bit sum out
  219.     sub    #.lsize    ,sp        ; allocate space for local data
  220.     mov    sp    ,r4        ; and point to it please
  221.     sub    #$allsiz,sp        ; /42/ allocate a HUGE buffer
  222.     call    waitsoh            ; wait for a packet to start
  223.     tst    r0            ; did it work or did we time out?
  224.     beq    10$            ; yes it worked
  225.     jmp    100$            ; we must have timed out then
  226.  
  227. 10$:    mov    sp    ,r3        ; the packet less SOH and checksum
  228.     mov    sp    ,.cbuff(r4)    ; /42/ save start address
  229.     call    rpakin            ; initialize things
  230.     call    rpakrd            ; read the next character from
  231.     bcs    100$            ; packet reader's buffer
  232.     bisb    r1    ,recbit        ; /43/ so we can determine parity set
  233.     bic    #^c<177>,r1        ; ensure parity is cleared out
  234.     movb    r1    ,(r3)+        ; *checkpacket++ = ch
  235.     unchar    r1    ,r0        ; get the length packet next please
  236.     mov    r0    ,.hdtype(r4)    ; /42/ save header type
  237.     cmp    r0    ,#2        ; /42/ if the length is 0,1 or 2 then
  238.     ble    20$            ; /42/ an extended header instead
  239.     sub    #2    ,r0        ; this is NOT an extended header so we
  240.     sub    chksiz    ,r0        ; will check to see if the packet can
  241.     bge    20$            ; hold at least SEQ+TYPE+CHECK
  242.     clr    r0            ; /44/ couldn't, "fix" bad length
  243. 20$:    mov    r0    ,.len(r4)    ; stuff the packet length
  244.  
  245.     call    rpakrd            ; as before, ask for the next char
  246.     bcs    100$            ; and take an error exit if need be
  247.     bisb    r1    ,recbit        ; /43/ so we can determine parity set
  248.     bic    #^c<177>,r1        ; ensure parity is cleared out
  249.     movb    r1    ,(r3)+        ; insert the sequence number into the
  250.     unchar    r1    ,.seq(r4)    ; checksum packet and save the SEQ
  251.  
  252.     call    rpakrd            ; read the TYPE field next, exiting
  253.     bcs    100$            ; on a read error, of course
  254.     bisb    r1    ,recbit        ; /43/ so we can determine parity set
  255.     bic    #^c<177>,r1        ; ensure parity is cleared out
  256.     movb    r1    ,(r3)+        ; save TYPE field into the checksum
  257.     mov    r1    ,.typ(r4)    ; and also into the field for return
  258.  
  259.     tst    .hdtype(r4)        ; /42/ NOW check for extended header
  260.     bne    30$            ; /42/ not extended header
  261.     call    rdexhd            ; /42/ ReaD EXtended HeaDer
  262.     tst    r0            ; /42/ did this work ok?
  263.     bne    110$            ; /63/ no, time-out or checksum error
  264.  
  265. 30$:    mov    .len(r4),.togo(r4)    ; loop for the data, if any
  266.     cmp    .togo(r4),4(r5)        ; /62/ ensure we don't overwrite buff
  267.     blos    40$            ; /62/ received length is ok
  268.     mov    4(r5)    ,.togo(r4)    ; /62/ bad length, do max possible..
  269. 40$:    mov    @r5    ,r2        ; point to the buffer now
  270.  
  271. 50$:    tst    .togo(r4)        ;   for i := 1 to len do
  272.     beq    90$            ;    begin
  273.     call    rpakrd            ;     read(input,ch)
  274.     bcs    100$            ;     exit if error
  275.     tst    parity            ; /62/ parity set to none?
  276.     bne    60$            ; /62/ no, must be some other type
  277.     tst    image            ; /62/ no parity, image mode today?
  278.     bne    70$            ; /62/ yes, leave things alone please
  279. 60$:    bic    #^c<177>,r1        ; /62/ ch := ch and chr(177b)
  280. 70$:    cmp    .size(r4),#maxlng    ;     if currentsize < maxpaksize
  281.     bhis    80$            ;       then
  282.     movb    r1    ,(r2)+        ;         data[i]  := ch
  283.     movb    r1    ,(r3)+        ;         checkpacket++ := ch
  284.                     ;    end
  285. 80$:    inc    .size(r4)        ;     currentsize:=succ(currentsize)
  286.     dec    .togo(r4)        ;    nchar_left := nchar_left-1
  287.     br    50$            ;    end
  288.  
  289. 90$:    clrb    @r2            ;   data[len] := null
  290.     clrb    @r3            ;   checkpacket++ := null
  291.     mov    sp    ,r3        ;   reset base address of checkpacket
  292.     call    rpakck            ;   read the checksum now
  293.     bcs    100$            ;   exit on error or time-out
  294.     call    rpakfi            ; /62/ finish the checksum
  295.     br    120$
  296.  
  297. 100$:    mov    2(r5)    ,r1        ; time-out error, flag no packet
  298.     mov    #timout    ,o$typ(r1)    ; return as pseudo packet type
  299.     mov    #timout    ,.typ(r4)    ; ditto for rpakst
  300.     clr    o$len(r1)        ; /62/ time-out has no length
  301.     clr    .len(r4)        ; /62/ don't log bogus data either
  302.     clr    .seq(r4)        ; /62/ time-out has no packet number
  303. 110$:    call    rpakst            ; do stats and disk dumping now
  304.  
  305. 120$:    add    #.lsize+$allsiz,sp    ; /42/ pop local buffers
  306.     unsave    <r4,r3,r2,r1>
  307.     return
  308.  
  309.  
  310.     .sbttl    RPACK$ wait for a start of packet char (SOH)
  311.  
  312. ;    W A I T S O H
  313. ;
  314. ;    output:      r0    = if <>, error code
  315. ;          r1    = the SOH or a null if we timed out
  316.  
  317. ; /BBS/    ^Z exit changed to ^C abort (requires two successive ^Cs)
  318.  
  319. waitsoh:clr    r1            ; start with nothing
  320.     clr    -(sp)            ; /56/ hold virgin copy of data
  321.     mov    #2    ,-(sp)        ; /BBS/ counter for ^C's
  322. 10$:    cmpb    r1    ,recsop        ; wait for a packet header please
  323.     beq    60$            ; got one, exit
  324.     mov    sertim    ,r0        ; /62/ if waiting for server command
  325.     bne    20$            ; /62/ then use that time-out
  326.     movb    senpar+p.time,r0    ; /62/ else use "normal" time-out
  327. 20$:    calls    binrea    ,<r0>        ; read with time-out
  328.     tst    r0            ; did the read work?
  329.     bne    50$            ; oops, just exit then
  330.     mov    r1    ,2(sp)        ; /56/ save it
  331.     bic    #^c<177>,r1        ; /44/ never want parity here
  332.     cmpb    r1    ,#'C&37        ; /BBS/ ^C returned?
  333.     bne    30$            ; /41/ no
  334.     dec    (sp)            ; /44/ should we really exit now?
  335.     bne    40$            ; /44/ no, in case we got some noise
  336.     mov    cc$max    ,cccnt        ; /BBS/ force abort thru cptln routine
  337.     mov    sp    ,ccflag        ; /BBS/ else .spcps will bomb..
  338.     mov    #er$nin    ,r0        ; /BBS/ a fake time-out until
  339.     br    50$            ; /BBS/ the ccast hits (15. ticks max)
  340. 30$:    mov    #2    ,(sp)        ; /BBS/ need TWO ^C's in a row to exit
  341. 40$:    call    rawio            ; all's not well, perhaps dump packets
  342.     br    10$            ; loop back for finding a packet start
  343. 50$:    clr    r1            ; time-out, return a null
  344.     br    70$            ; /56/
  345. 60$:    tstb    2(sp)            ; /62/ parity perhaps?
  346.     bpl    70$            ; /62/ no
  347.     tst    parity            ; /BBS/ 8-bit channel?
  348.     bne    70$            ; /56/ no
  349.     tst    incpar            ; /62/ warning already done?
  350.     bne    70$            ; /62/ ya, avoid rollover to zero..
  351.     inc    incpar            ; /56/ ya, also want message only once
  352. 70$:    cmp    (sp)+    ,(sp)+        ; /BBS/ pop ^C counter, data buffer
  353.     return
  354.  
  355.  
  356.     .sbttl    RPACK$ initialization
  357.  
  358. rpakin:    mov    r4    ,r0        ; /62/ copy local buffer pointer
  359.     mov    #11    ,r1        ; /62/ need to clear this many words
  360. 10$:    clr    (r0)+            ; /62/ do it
  361.     sob    r1    ,10$        ; /62/ one word at a time
  362.     bisb    senpar+p.time,.timeo(r4) ; /62/ time-out := SET TIME-OUT value
  363.     mov    2(r5)    ,r0
  364.     clr    (r0)+            ; packet.length := 0
  365.     clr    (r0)+            ; packet.number := 0
  366.     clr    (r0)+            ; packet.type   := 0
  367.     return
  368.  
  369.  
  370.     .sbttl    RPACK$ read with time-out
  371.  
  372. rpakrd:    calls    binrea    ,<.timeo(r4)>    ; read input char
  373.     tst    r0            ; did it work?
  374.     bne    10$            ; no
  375.     call    rawio            ; perhaps raw I/O logging
  376.     clr    r0            ; no errors, also clears carry
  377.     return
  378. 10$:    sec                ; flag the time-out
  379.     return
  380.  
  381.  
  382.     .sbttl    RPACK$ extended header type 0 for long packets
  383.  
  384. rdexhd:    mov    r2    ,-(sp)        ; /42/ added 08-Jan-86 Brian Nelson
  385.     mov    r5    ,-(sp)        ; need an odd register for mul
  386.     call    rpakrd            ; extended header, read the lenx1
  387.     bcs    20$            ; field, exiting on read errors
  388.     bic    #^c<177>,r1        ; ensure parity is cleared out
  389.     movb    r1    ,(r3)+        ; save into checksum buffer
  390.     unchar    r1    ,r5        ; get the high order of length
  391.     mul    #95.    ,r5        ; shift over please
  392.     call    rpakrd            ; extended header, read the lenx2
  393.     bcs    20$            ; field, exiting on read errors
  394.     bic    #^c<177>,r1        ; ensure parity is cleared out
  395.     movb    r1    ,(r3)+        ; save into checksum buffer
  396.     unchar    r1    ,r1        ; get the next one
  397.     add    r1    ,r5        ; now we have the extended length
  398.     sub    chksiz    ,r5        ; drop it by checksum size
  399.     mov    r5    ,.len(r4)    ; save it here, of course
  400.  
  401.     mov    .cbuff(r4),r5        ; now, at last, get the extended
  402.     mov    #5    ,r1        ; header checksum data
  403.     clr    -(sp)            ; accumulate in stack
  404. 10$:    clr    r0            ; use the normal safe way to add
  405.     bisb    (r5)+    ,r0        ; bytes even though we know that
  406.     add    r0    ,(sp)        ; no sign extends will happen
  407.     sob    r1    ,10$        ; next please
  408.     mov    (sp)+    ,r0        ; pop the checksum please
  409.     mov    r0    ,r2        ; save it
  410.     bic    #^c<300>,r2        ; compute it as in:
  411.     ash    #-6    ,r2        ; chk=char((s+((s&0300)/0100))&77)
  412.     add    r0    ,r2
  413.     bic    #^c<77>    ,r2        ; got it now
  414.  
  415.     call    rpakrd            ; extended header - read the hcheck
  416.     bcs    20$            ; field, exiting on read errors
  417.     clr    r0            ; /63/ preset no error
  418.     bic    #^c<177>,r1        ; ensure parity is cleared out
  419.     movb    r1    ,(r3)+        ; save into checksum buffer
  420.     unchar    r1    ,r1        ; convert to actual checksum now
  421.     cmpb    r1    ,r2        ; do the checksums match?
  422.     beq    40$            ; /63/ yes
  423.     mov    #badchk    ,r0        ; header checksum error
  424.     br    30$            ; stuff the error
  425. 20$:    mov    #timout    ,r0        ; return time-out error
  426.     clr    .len(r4)        ; /62/ don't log bogus data on timout
  427. 30$:    mov    2(sp)    ,r5        ; /BBS/ restore r5 to as entering
  428.     mov    2(r5)    ,r1        ; get address of result block
  429.     clr    o$len(r1)        ; clear packet length
  430.     mov    r0    ,o$typ(r1)    ; return the error
  431.     mov    r0    ,.typ(r4)    ; here also please
  432.     mov    #-1    ,r0        ; fatal error
  433. 40$:    mov    (sp)+    ,r5
  434.     mov    (sp)+    ,r2
  435.     return
  436.  
  437.  
  438.     .sbttl    RPACK$ get and convert the checksum
  439.  
  440. rpakck:    save    <r3>            ; use r3 for accumulating check
  441.     clr    r3            ; assume zero for now
  442.     call    rpakrd            ; read(input,ch)
  443.     bcs    20$            ; exit if timed out
  444.     bisb    r1    ,recbit        ; recbit |= ch
  445.     bic    #^c<177>,r1        ; ch := ch and 177b
  446.     unchar    r1    ,r3        ; received_check := ch
  447.     cmpb    chktyp    ,#defchk    ; if len(checksum) > 8 bits
  448.     blos    10$            ;  then begin
  449.      ash    #6    ,r3        ;   check := check * 64
  450.      call    rpakrd            ;   read(input,ch)
  451.      bcs    20$            ;   exit if timed out
  452.      bic    #^c<177>,r1        ;   ch := ch and 177b
  453.      unchar    r1    ,r1        ;   ch := unchar(ch)
  454.      bisb    r1    ,r3        ;   rcheck := rcheck + ch
  455.      cmpb    chktyp    ,#'3        ;   if checktype = crc16
  456.      bne    10$            ;    then
  457.      ash    #6    ,r3        ;     begin
  458.      call    rpakrd            ;      check := check * 64
  459.      bcs    20$            ;      check := check + ch
  460.      bic    #^c<177>,r1        ;      ch := ch and 177b
  461.      unchar    r1    ,r1
  462.      bisb    r1    ,r3        ;      end
  463. 10$:    clc
  464. 20$:    mov    r3    ,.rcheck(r4)    ; return the checksum
  465.     unsave    <r3>
  466.     return
  467.  
  468.  
  469.     .sbttl    RPACK$ end of packet housekeeping
  470.  
  471. rpakfi:    mov    r3    ,-(sp)        ; compute correct checksum type
  472.     call    checks            ; simple
  473.     mov    (sp)+    ,.ccheck(r4)    ; and stuff it in please
  474.     cmpb    .ccheck(r4),.rcheck(r4)    ; compare computed, actual checksums
  475.     beq    10$            ; they are the same
  476.     mov    #badchk    ,.typ(r4)    ; they're different, flag the error
  477. 10$:    mov    2(r5)    ,r1        ; where to return some things
  478.     mov    .len(r4),(r1)+        ; /62/ O$LEN packet length
  479.     mov    .seq(r4),(r1)+        ; /62/ O$SEQ packet number
  480.     mov    .typ(r4),(r1)        ; /62/ O$TYP packet type
  481.     call    rpakst            ; do stats and logging now
  482.     jmp    rpaklo            ; /62/ possibly log checksum errors?
  483.  
  484.  
  485.     .sbttl    RPACK$ statistics, logging, resonating packets fix
  486.  
  487. rpakst:    cmpb    .typ(r4),#'A&137    ; count the packet types for stats
  488.     blo    40$            ; bad packet type
  489.     cmpb    .typ(r4),#'Z&137    ; must in the range A..Z
  490.     bhi    40$            ; definitely a bad packet
  491.  
  492.     ; /BBS/ check for resonating packets or hung driver
  493.     asr    nakrec            ; shift prior tests down the line
  494.     cmpb    .typ(r4),#'N&137    ; a NAK?
  495.     bne    10$            ; nope..
  496.     bis    #4    ,nakrec        ; ya, mark shift reg at 1st position
  497. 10$:    cmp    nakrec    ,#4+1        ; looking for NAK xxx NAK series as
  498.     bge    20$            ; when resonating, go clear it
  499.     cmpb    .typ(r4),#timout    ; timed out?
  500.     bne    30$            ; nope..
  501. 20$:    call    hose            ; ya, try harder to make it go
  502.     clr    nakrec            ; start over after hose
  503.     bit    #log$rp    ,trace        ; /BBS/ RPACK to TT?
  504.     beq    30$            ; /BBS/ no
  505.     wrtall    #pak.03            ; /62/ ya, display time out
  506.  
  507. 30$:     movb    .typ(r4),r1        ; packet is ok, add it to the stats
  508.      sub    #100    ,r1        ; convert to 1..26
  509.      asl    r1            ; to word offsets
  510.      asl    r1            ; /43/ double word offsets
  511.      add    #1    ,pcnt.r+2(r1)    ; /43/ 32-bit addition today
  512.      adc    pcnt.r+0(r1)        ; /43/ the high order part of it
  513.      add    #1    ,pcnt.r+2    ; /43/ add it in here also
  514.      adc    pcnt.r+0        ; /43/ high order part
  515.  
  516. 40$:    bit    #log$rp    ,trace        ; /BBS/ RPACK to TT?
  517.     beq    50$            ; /BBS/ no
  518.     .newline            ; /BBS/ ya, format display
  519. 50$:    bit    #log$pa    ,trace        ; tracing today?
  520.     bne    60$            ; /BBS/ ya
  521.     bit    #log$de    ,trace        ; /62/ TT debugging?
  522.     beq    70$            ; /BBS/ no
  523. 60$:    calls    dskdmp    ,<#pak.02,.seq(r4),.typ(r4),.len(r4),@r5> ; /62/
  524. 70$:    return
  525.  
  526.  
  527.     .sbttl    RPACK$ packet logging
  528.  
  529. rpaklo:    cmp    .rcheck(r4),.ccheck(r4)    ; checksums match?
  530.     beq    40$            ; /62/ yes, do nothing then
  531.     save    <r0,r1>            ; /62/
  532.     mov    trace    ,r0        ; /62/ copy of debug status word
  533.     bic    #^c<log$pa!log$de>,r0    ; /62/ need to do this?
  534.     beq    30$            ; /62/ nope
  535.     sub    #100.    ,sp        ; /63/ ya, make buffer for err message
  536.     mov    sp    ,r1        ; point to the buffer
  537.     strcpy    r1    ,#pak.04    ; /62/ a header
  538.     strlen    r1            ; length so far
  539.     add    r0    ,r1        ; point to the end of it
  540.     deccvt    .rcheck(r4),r1        ; convert to decimal
  541.     add    #6    ,r1        ; move along please
  542.     movb    #comma    ,(r1)+        ; /62/ insert delimiter
  543.     deccvt    .ccheck(r4),r1        ; the calculated checksum
  544.     add    #6    ,r1        ; make it .asciz
  545.     clrb    @r1            ; simple
  546.     mov    sp    ,r1        ; point back to the buffer
  547.     bit    #log$pa    ,trace        ; /62/ is packet debugging on?
  548.     beq    10$            ; /62/ no
  549.     strlen    r1            ; ya, get the length
  550.     calls    putrec    ,<r1,r0,#lun.lo> ; dump buffer to disk
  551.     tst    r0            ; /62/ did it work?
  552.     beq    10$            ; /62/ ya
  553.     call    logerr            ; /62/ no, handle the error
  554. 10$:    tst    remote            ; /62/ running locally?
  555.     bne    20$            ; /62/ no
  556.     bit    #log$de    ,trace        ; /62/ ya, is terminal debugging on?
  557.     beq    20$            ; /62/ no
  558.     wrtall    r1            ; /62/ ya, print it
  559.     .newline            ; /62/
  560. 20$:    add    #100.    ,sp        ; /63/ pop buffer
  561. 30$:    unsave    <r1,r0>            ; /62/
  562. 40$:    return
  563.  
  564.  
  565.     .sbttl    RPACK$ raw I/O logging, chars to RPACK debug display
  566.  
  567. rawio:    save    <r0,r1>
  568.     bit    #log$io    ,trace        ; dumping all I/O today?
  569.     beq    20$            ; /BBS/ no
  570.     save    <r1>
  571.     clr    r0            ; avoid sxt
  572.     bisb    r1    ,r0        ; and setup call to putcr0
  573.     mov    #lun.lo    ,r1        ; write to this channel
  574.     call    putcr0            ; simple
  575.     tst    r0            ; /62/ did it work?
  576.     beq    10$            ; /62/ ya
  577.     call    logerr            ; /62/ no, handle the error
  578. 10$:    unsave    <r1>            ; /62/
  579.  
  580. 20$:    bit    #log$rp    ,trace        ; /BBS/ dump to a local terminal?
  581.     beq    60$            ; no
  582.     cmpb    r1    ,recsop        ; start of a packet?
  583.     beq    50$            ; yes
  584.     cmpb    r1    ,conpar+p.eol    ; /BBS/ no, is this the end of line?
  585.     bne    30$            ; /BBS/ no
  586.     wrtall    #pak.06            ; /62/ yes, finish up the display
  587.     br    60$
  588.  
  589. 30$:    tst    tsxsav            ; /BBS/ running under TSX?
  590.     beq    40$            ; /BBS/ nope
  591.     cmpb    r1    ,m.tsxr        ; /62/ ya, is this the TSLICH?
  592.     beq    60$            ; /BBS/ ya, don't type it to TT
  593. 40$:    movb    r1    ,r0        ; /BBS/ get a byte
  594.     call    writ1char        ; /BBS/ send it to TT
  595.     br    60$
  596.  
  597. 50$:    wrtall    #pak.05            ; /62/ start of a packet
  598. 60$:    unsave    <r1,r0>
  599.     return
  600.  
  601.  
  602.     .sbttl    Send a packet
  603.  
  604. ;    S P A C K $
  605. ;
  606. ;    input:      (r5)    = type of packet
  607. ;         2(r5)    = packet number
  608. ;         4(r5)    = length of the data to send
  609. ;         6(r5)    = location of the data to send
  610. ;    output:       r0    = error status
  611.  
  612. spack$::save    <r1,r2,r3,r4>
  613.     call    dcdtst            ; /62/ check DCD, report any change..
  614.     tstb    handch            ; /62/ any particular handshake today?
  615.     beq    10$            ; no
  616.     call    spakwa            ; ya, do handshaking
  617. 10$:    call    spakin            ; logging, padding, packet type stats
  618.     sub    #$allsiz,sp        ; /42/ allocate a LONG buffer
  619.     mov    sp    ,r4        ; point to the buffer
  620.     clr    -(sp)            ; count the total length
  621.     tst    prexon            ; /53/ prefix all packets with an XON?
  622.     beq    20$            ; /53/ no
  623.     movb    #xon    ,(r4)+        ; /53/ yes, insert one
  624.     inc    @sp            ; /53/ write_length++
  625. 20$:    setpar    sensop    ,(r4)+        ; start all packets with the SOH
  626.     mov    r4    ,r2        ; get address for checksum compute
  627.     inc    @sp            ; packetlength := succ(packetlength)
  628.     mov    4(r5)    ,r0        ; the length of the packet
  629.     mov    #maxpak    ,r1        ; /BBS/ preset for compare
  630.     cmp    senlng    ,r1        ; /BBS/ long packets this time?
  631.     blos    30$            ; /BBS/ nope..
  632.     sub    chksiz    ,r1        ; /BBS/ ya, be sure checksum will fit
  633.     sub    #2    ,r1        ; /BBS/ SEQ + TYP have to fit too..
  634. 30$:    cmp    r0    ,r1        ; /BBS/ packet too large?
  635.     blos    50$            ; no
  636.     tst    senlng            ; /42/ receiver said it can do long
  637.     beq    40$            ; /42/ packets?  if eq, no
  638.                     ; /42/ otherwise build extended header
  639.     mov    r2    ,-(sp)        ; /42/ save address of start of packet
  640.     mov    #space    ,-(sp)        ; /42/ accumulate header checksum
  641.     setpar    #space    ,(r4)+        ; /42/ length is a space, of course
  642.     tochar    2(r5)    ,r1        ; /42/ packet sequence please
  643.     add    r1    ,(sp)        ; /42/ add into header checksum now
  644.     setpar    r1    ,(r4)+        ; /42/ insert it
  645.     movb    (r5)    ,r1        ; /42/ the packet type is next
  646.     bicb    #40    ,r1        ; /42/ ensure always upper case
  647.     add    r1    ,(sp)        ; /42/ add in the checksum
  648.     setpar    r1    ,(r4)+        ; /42/ and insert that also
  649.     mov    r0    ,r3        ; /42/ insert the total packet size
  650.     clr    r2            ; /42/ first byte is size/95
  651.     add    chksiz    ,r3        ; /42/ must include checksum size
  652.     div    #95.    ,r2        ; /42/ second byte is size mod 95
  653.     tochar    r2    ,r2        ; /42/ convert to character rep
  654.     tochar    r3    ,r3        ; /42/ convert to character rep
  655.     setpar    r2    ,(r4)+        ; /42/ insert high bits into packet
  656.     add    r2    ,(sp)        ; /42/ add into checksum
  657.     setpar    r3    ,(r4)+        ; /42/ insert low bits into packet
  658.     add    r3    ,(sp)        ; /42/ add into checksum
  659.     mov    (sp)+    ,r0        ; /42/ pop the checksum please
  660.     mov    r0    ,r2        ; /42/ save it
  661.     bic    #^c<300>,r2        ; /42/ compute it as in:
  662.     ash    #-6    ,r2        ; /42/ checksum=
  663.     add    r0    ,r2        ; /42/ char((s+((s&300)/100))&77)
  664.     bic    #^c<77>    ,r2        ; /42/ got it now
  665.     tochar    r2    ,r2        ; /42/ convert checksum to character
  666.     setpar    r2    ,(r4)+        ; /42/ and insert into packet
  667.     mov    (sp)+    ,r2        ; /42/ start checksum for rest here
  668.     add    #7    ,(sp)        ; /BBS/ add, in case of prexon, above
  669.     br    60$            ; /42/ add off we go
  670.  
  671. 40$:    mov    #maxpak-3,r0        ; yes, reset packet size please
  672. 50$:    add    #2    ,r0        ; + two for number and type
  673.     add    chksiz    ,r0        ; + the length of the checksum please
  674.     clr    r1            ; accumulated checksum
  675.     tochar    r0    ,r1        ; start the checksum out right
  676.     setpar    r1    ,(r4)+        ; and stuff length into the packet
  677.     inc    @sp            ; packetlength := succ(packetlength)
  678.     tochar    2(r5)    ,r0        ; convert the packet number now
  679.     setpar    r0    ,(r4)+        ; and stuff it into the packet
  680.     inc    @sp            ; packetlength := succ(packetlength)
  681.     movb    @r5    ,r0        ; get the packet type now
  682.     bicb    #40    ,r0        ; ensure UPPER CASE packet type
  683.     setpar    r0    ,(r4)+        ; insert the packet type into buffer
  684.     inc    @sp            ; packetlength := succ(packetlength)
  685.  
  686. 60$:    mov    4(r5)    ,r1        ; get the data length
  687.     beq    80$            ; nothing to do
  688.     mov    6(r5)    ,r3        ; address of the data to send
  689.  
  690. 70$:    clr    r0            ; get the next character
  691.     bisb    (r3)+    ,r0        ; next char
  692.     setpar    r0    ,(r4)+        ; now move the data byte into the buff
  693.     inc    @sp            ; packetlength := succ(packetlength)
  694.     sob    r1    ,70$        ; next please
  695.  
  696. 80$:    clrb    @r4            ; set .asciz for call to checks
  697.     mov    r2    ,-(sp)        ; starting address for checksum field
  698.     call    checks            ; simple
  699.     mov    (sp)+    ,r2        ; get the computed checksum now
  700.     call    spakck            ; stuff checksum into buffer now
  701.     add    r0    ,@sp        ; and the length of the checksum
  702.     setpar    conpar+p.eol,(r4)+    ; end of line
  703.     inc    @sp            ; packetlength := succ(packetlength)
  704.     mov    (sp)+    ,r1        ; packet length
  705.     mov    sp    ,r4        ; address(buffer)
  706.     calls    binwri    ,<r4,r1>    ; and dump the buffer out now
  707.     call    spakfi            ; log to disk
  708.     add    #$allsiz,sp        ; pop the buffer
  709.     unsave    <r4,r3,r2,r1>
  710.     return
  711.  
  712.  
  713.     .sbttl    SPACK$ handshaking
  714.  
  715. spakwa:    scan    @r5    ,#han.no    ; if packet type is in this list..
  716.     tst    r0
  717.     bne    30$            ; ..then skip the handshaking stuff
  718.     save    <r2>
  719.     mov    4(r5)    ,r2        ; /62/ limit looping to packet length
  720.     add    #14    ,r2        ; /62/ plus header, trailer, etc..
  721.     movb    senpar+p.time,r0    ; /62/ use "normal" time-out
  722. 10$:    calls    binrea    ,<r0>        ; /62/ wait for handshake char
  723.     tst    r0            ; did the read time out?
  724.     bne    20$            ; /62/ if so, exit
  725.     bicb    #200    ,r1        ; ensure no parity is set
  726.     cmpb    r1    ,handch        ; is this the handshake character?
  727.     beq    20$            ; /62/ ya
  728.     sob    r2    ,10$        ; no, try again but not forever please
  729. 20$:    unsave    <r2>
  730. 30$:    return
  731.  
  732.     .save                ; these packet types must NOT
  733.     .psect    $pdata            ; be processed with handshaking
  734. han.no:    .byte    msg$snd    ,msg$ser ,msg$rcv ,msg$command ,msg$generic
  735.     .byte    0
  736.     .even
  737.     .restore
  738.  
  739.  
  740.     .sbttl    SPACK$ logging, padding, packet type stats
  741.  
  742. spakin:    bit    #log$pa    ,trace        ; packet debugging today?
  743.     bne    10$            ; /BBS/ ya
  744.     bit    #log$de    ,trace        ; /62/ no, maybe TT debugging?
  745.     beq    20$            ; /BBS/ no
  746. 10$:    calls    dskdmp    ,<#pak.08,2(r5),@r5,4(r5),6(r5)> ; /62/ ya
  747.  
  748. 20$:    tst    pauset            ; wait a moment?
  749.     beq    30$            ; no
  750.     calls    suspend    ,<pauset>    ; yes
  751. 30$:    clr    r1            ; avoid sign extension
  752.     bisb    conpar+p.npad,r1    ; send some pad characters?
  753.     beq    50$            ; no padding
  754.     mov    #conpar+p.padc,r2    ; /62/ address of the pad character
  755. 40$:    calls    binwri    ,<r2,#1>    ; send some padding
  756.     sob    r1    ,40$        ; next please
  757.  
  758. 50$:    movb    @r5    ,r1        ; the packet type next
  759.     cmpb    r1    ,#'A&137    ; a legitimate packet type?
  760.     blo    60$            ; no
  761.     cmpb    r1    ,#'Z&137    ; must be in the range A..Z
  762.     bhi    60$            ; no good
  763.      sub    #100    ,r1        ; convert into range 1..26
  764.      asl    r1            ; and count the packet type
  765.      asl    r1            ; /43/ 32. bits
  766.      add    #1    ,pcnt.s+2(r1)    ; /43/ 32. bits, pakcnt(type)++
  767.      adc    pcnt.s+0(r1)        ; /43/ 32. bits, the high part
  768.      add    #1    ,pcnt.s+2    ; /43/ 32. bits now
  769.      adc    pcnt.s+0        ; /43/ the high order part
  770. 60$:    return
  771.  
  772.  
  773.     .sbttl    SPACK$ compute checksum
  774.  
  775. spakck:    clr    r0        ; checksum.len := 0
  776.     cmpb    chktyp    ,#defchk ; if checklength > 6 bits
  777.     blos    20$        ;  then begin
  778.     cmpb    chktyp    ,#'3    ;   if checktype = crc16
  779.     bne    10$        ;    then begin
  780.     mov    r2    ,r1    ;     checkchar1:=tochar(check[12..15])
  781.      ash    #-14    ,r1    ;     shift over 12 bits
  782.      bic    #^c<17>    ,r1    ;     mask off the high 12  bits
  783.      tochar    r1    ,@r4
  784.      setpar    @r4    ,(r4)+
  785.      inc    r0        ;     packetlength := succ(packetlength)
  786.                 ;    end
  787. 10$:     mov    r2    ,r1    ;   checkchar1 := tochar(check[6..11])
  788.      ash    #-6    ,r1    ;   shift over 6 bits
  789.      bic    #^c<77>    ,r1    ;   mask off the higher order bits
  790.      tochar    r1    ,@r4
  791.      setpar    @r4    ,(r4)+
  792.      inc    r0        ;   packetlength := succ(packetlength)
  793.      bic    #^c<77>    ,r2    ;   now drop the high bits from checks
  794.  
  795. 20$:    tochar    r2    ,@r4    ; convert char
  796.     tst    ranerr        ; insert random checksum errors?
  797.     beq    40$        ; no, please don't
  798.     mov    r0    ,-(sp)    ;+ test mode  irand uses r0
  799.     call    irand        ;+ test mode  get a random number
  800.     tst    r0        ;+ test mode  is it zero?
  801.     bne    30$        ;+ test mode  no, leave things alone
  802.     incb    @r4        ;+ test mode  ya, create an error
  803. 30$:    mov    (sp)+    ,r0    ;+ test mode  restore r0
  804. 40$:    setpar    @r4    ,(r4)+    ; set parity, if in use..
  805.     inc    r0        ; packetlength := succ(packetlength)
  806.     return
  807.  
  808.  
  809.     .sbttl    SPACK$ pseudo random number generator for testing
  810.  
  811. irand:    tst    seed            ; has a seed been set?
  812.     bne    10$            ; ya, use that value
  813.     mov    #1234.    ,seed        ; no, use this default seed
  814. 10$:    mov    seed    ,r0        ; make a copy of it
  815.     mov    r1    ,-(sp)        ; preserve r1
  816.     mov    r0    ,r1        ; copy of seed number to
  817.     ash    #-4    ,r1        ; multiply it * 16. and
  818.     bic    #170000    ,r1        ; clear its bits 15. - 12. then
  819.     xor    r1    ,r0        ; toggle whatever's left in orig seed
  820.     ash    #13    ,r1        ; dump bits 11. thru 0.
  821.     bic    #100000    ,r1        ; ensure what's left is a positive num
  822.     xor    r1    ,r0        ; again, toggle the orig seed with it
  823.     bic    #100000    ,r0        ; make sure result remains positive
  824.     mov    r0    ,seed        ; save it for the next time around..
  825.     ash    #-13    ,r0        ; shift so only 4 hi bits are output
  826.     mov    (sp)+    ,r1        ; restore r1
  827.     return
  828.  
  829.  
  830.     .sbttl    SPACK$ log to disk
  831.  
  832. spakfi:    bit    #log$io    ,trace        ; dumping all I/O out?
  833.     beq    40$            ; no
  834.     save    <r0,r1,r2,r4>
  835.     mov    r1    ,r2        ; anything to do?
  836.     beq    30$            ; no
  837. 10$:    clr    r0            ; yes, avoid sign extension
  838.     bisb    (r4)+    ,r0        ; get the next ch to dump
  839.     mov    #lun.lo    ,r1        ; the lun to write to
  840.     call    putcr0            ; simple
  841.     tst    r0            ; /62/ did it work?
  842.     beq    20$            ; /62/ ya
  843.     call    logerr            ; /62/ no, handle the error
  844.     br    30$            ; /62/ then bail out
  845. 20$:    sob    r2    ,10$        ; next please
  846. 30$:    unsave    <r4,r2,r1,r0>
  847. 40$:    return
  848.  
  849.  
  850.     .sbttl    Compute checksum
  851.  
  852. ;    C H E C K S
  853. ;
  854. ;    input:      (sp)    = address of .asciz string to checksum
  855. ;    output:      (sp)    = the computed checksum
  856.  
  857. checks:    save    <r0,r1,r2,r3>
  858.     mov    10+2(sp),r2        ; pointer to the string to check
  859.     cmpb    chktyp    ,#'3        ; CRC-CCITT type today?
  860.     bne    10$            ; no
  861.     strlen    r2            ; yes, get the .asciz string length
  862.     calls    crcclc    ,<r2,r0>    ; compute the crc16
  863.     mov    r0    ,r2        ; stuff the result into r2 for later
  864.     br    60$            ; and exit
  865.  
  866. 10$:    clr    r1            ; init the checksum accumulator
  867. 20$:    clr    r3            ; get the next ch please
  868.     bisb    (r2)+    ,r3        ; got the next ch now
  869.     beq    40$            ; hit the end of the string
  870.     tst    parity            ; /BBS/ did the packet contain parity?
  871.     beq    30$            ; no, leave bit 7 alone
  872.     bic    #^c<177>,r3        ; yes, please clear bit seven
  873. 30$:    bic    #170000    ,r1        ; /42/ ensure long packet not overflow
  874.     add    r3    ,r1        ; check := check + ch
  875.     br    20$
  876.  
  877. 40$:    mov    r1    ,r2        ; checksum := ((checksum and 300B)/64)
  878.     cmpb    chktyp    ,#'2        ; 12 bit sum type checksum?
  879.     beq    50$            ; yes, just exit
  880.     bic    #^c<300>,r2        ; ((..+checksum) and 77b)
  881.     ash    #-6    ,r2
  882.     add    r1    ,r2
  883.     bic    #^c<77>    ,r2
  884.     br    60$
  885.  
  886. 50$:    bic    #170000    ,r2        ; type 2 checksum
  887. 60$:    mov    r2    ,10+2(sp)    ; return the checksum
  888.     unsave    <r3,r2,r1,r0>
  889.     return
  890.  
  891.  
  892.     .sbttl    CRC calculation
  893.  
  894. ;    This routine will calculate the CRC for a string using the
  895. ;    CRC-CCIT polynomial.
  896. ;
  897. ;    The string should be the fields of the packet between  but
  898. ;    not including the  <mark>  and  the  block check, which is
  899. ;    treated as a string of bits with the low order bit of  the
  900. ;    first  character  first and the high order bit of the last
  901. ;    character last --  this  is  how  the  bits  arrive on the
  902. ;    transmission  line.  The  bit  string  is  divided by  the
  903. ;    polynomial
  904. ;
  905. ;    x^16+x^12+x^5+1
  906. ;
  907. ;    The initial value of the  CRC  is  0.  The  result  is the
  908. ;    remainder  of  this   division,   used   as-is  (i.e.  not
  909. ;    complemented).
  910. ;
  911. ;    From 20KERMIT.MAC, rewritten for  PDP-11  by  Brian Nelson
  912. ;    13-Jan-84 08:50:43
  913. ;
  914. ;    input:      (r5)    = string address
  915. ;         2(r5)    = string length
  916. ;    output:       r0    = CRC
  917.  
  918. crcclc:    save    <r1,r2,r3,r4,r5>
  919.     clr    r0            ; initialize the CRC to zero
  920.     mov    @r5    ,r3        ; get the string address now
  921.     mov    2(r5)    ,r4        ; get the string length
  922.     beq    30$            ; oops, nothing to do then
  923.  
  924. 10$:    clr    r1            ; get the next character please
  925.     bisb    (r3)+    ,r1        ; please avoid PDP-11 sign extend
  926.     tst    parity            ; /BBS/ did the packet have parity?
  927.     beq    20$            ; no, leave bit seven alone
  928.     bic    #^c<177>,r1        ; yes, clear bit seven please
  929. 20$:    ixor    r0    ,r1        ; add in with the current CRC
  930.     mov    r1    ,r2        ; get the high four bits
  931.     ash    #-4    ,r2        ; and move them over to 3..0
  932.     bic    #^c<17>    ,r2        ; drop any bits left over
  933.     bic    #^c<17>    ,r1        ; and the low four bits
  934.     asl    r1            ; times 2 for
  935.     asl    r2            ; word addressing
  936.     mov    crctb2(r1),r1        ; get low portion of CRC factor
  937.     ixor    crctab(r2),r1        ; ixor avoids hardware xor mode limits
  938.     swab    r0            ; shift off a byte from previous CRC
  939.     bic    #^c<377>,r0        ; clear new high byte
  940.     ixor    r1    ,r0        ; add in the new value
  941.     sob    r4    ,10$        ; next please
  942.  
  943. 30$:    unsave    <r5,r4,r3,r2,r1>
  944.     return
  945.  
  946.     .save
  947.     .psect    $pdata
  948. crctab:    .word         0 ,010201 ,020402 ,030603 ,041004 ,051205 ,061406 ,071607
  949.     .word    102010 ,112211 ,122412 ,132613 ,143014 ,153215 ,163416 ,173617
  950. crctb2:    .word         0 ,010611 ,021422 ,031233 ,043044 ,053655 ,062466 ,072277
  951.     .word    106110 ,116701 ,127532 ,137323 ,145154 ,155745 ,164576 ,174367
  952.     .restore
  953.  
  954.  
  955.     .sbttl    Buffer file being sent    ; /63/ moved back here for speed..
  956.  
  957. ;    B U F F I L              /63/ patched to include BUFPAK
  958. ;
  959. ;    input:     (r5)    = #0 for file or null terminated source buffer address
  960. ;        2(25)    = destination buffer, will be null terminated
  961. ;    output:      r0    = if <>, RMS error code
  962. ;          r1    = returned string length, excluding null terminator
  963. ;
  964. ;    Control and 8-bit char prefixing and repeat count encoding done here.
  965.  
  966. buffil::save    <r2,r3,r4>        ; /63/
  967.     mov    2(r5)    ,r4        ; destination buffer address
  968.     mov     (r5)    ,r5        ; /63/ source buff addr or 0 if a file
  969.     clr    r3            ; init a string length counter
  970.     mov    senlng    ,r2        ; /63/ long_packets on?   or clears r2
  971.     bne    10$            ; /62/ ya..  to avoid sxt on next inst
  972.     bisb    conpar+p.spsiz,r2    ; /63/ get receiver's max size
  973. 10$:    cmp    r2    ,senlen        ; /63/ rec'd packet_len > SET SEN PAC?
  974.     ble    20$            ; /62/ no
  975.     mov    senlen    ,r2        ; /63/ ya, let SET SEN PAC prevail
  976. 20$:    sub    #10    ,r2        ; /63/ allow for rpt quoting, etc, etc
  977.  
  978. 30$:    tst    dorpt            ; are we doing repeat counts?
  979.     beq    100$            ; no
  980.  
  981. 40$:    call    gnc            ; get next character
  982.     bcs    60$            ; hit the end of the file
  983.     tst    rptinit            ; if first time through this loop
  984.     beq    50$            ; then
  985.     clr    rptinit            ; flag we've been here now
  986.     clr    rptcount        ; init the repeatt count
  987.     movb    r1    ,rptlast    ; save copy of char in rptlast buffer
  988. 50$:    cmpb    r1    ,rptlast    ; if the current char = rptlast char
  989.     bne    60$            ; then
  990.     cmp    rptcount,#maxpak    ; reached the mex repeat count yet?
  991.     bge    60$            ; ya..
  992.     inc    rptcount        ; no, bump the repeat count
  993.     br    40$            ; and loop
  994.  
  995. 60$:    mov    r1    ,rptsave    ; save the failed character please
  996.     tst    rptcount        ; this may be EOF on first character
  997.     beq    120$            ; if so, we simply do nothing at all
  998.     cmp    rptcount,#2        ; please don't bother with ONE char
  999.     bgt    80$            ; don't waste the overhead for two
  1000. 70$:    clr    r1            ; avoid sign extension please
  1001.     bisb    rptlast    ,r1        ; get the character to write
  1002.     call    140$            ; and stuff it into the buffer
  1003.     dec    rptcount        ; more to insert?
  1004.     bne    70$            ; yes
  1005.     br    90$            ; no, exit
  1006.  
  1007. 80$:    movb    rptquo    ,(r4)+        ; insert the repeat count quote
  1008.     inc    r3            ; count it in the packet size
  1009.     tochar    rptcount,(r4)+        ; convert the repeat count to a char
  1010.     inc    r3            ; and count in the packet size
  1011.     clr    r1            ; avoid sxt
  1012.     bisb    rptlast    ,r1        ; recover the repeated character
  1013.     call    140$            ; and insert it into the buffer
  1014. 90$:    movb    rptsave    ,rptlast    ; make the failing character the one
  1015.     clr    rptcount        ; in case of EOF, set this please
  1016.     tst    r0            ; was this the end of file?
  1017.     bne    120$            ; yes, we had better leave then
  1018.     inc    rptcount        ; no, initialize the count please
  1019.     br    110$            ; and check for overflow in the buffer
  1020.  
  1021. 100$:    call    gnc            ; get next char
  1022.     bcs    120$            ; if (EOF) then break
  1023.     call    140$            ; stuff the character w/o repeats
  1024. 110$:    cmp    r3    ,r2        ; /63/ room for more data?
  1025.     blo    30$            ; ya
  1026.  
  1027. 120$:    mov    r3    ,r1        ; return the length please
  1028.     beq    130$            ; nothing there
  1029.     clr    r0            ; say read was successful
  1030. 130$:    clrb    (r4)            ; /63/ null term for non-file usage
  1031.     unsave    <r4,r3,r2>        ; /63/ is harmless for file packets
  1032.     return
  1033.  
  1034.  
  1035.     .sbttl    Actually quote and stuff the char for BUFFIL
  1036.  
  1037. 140$:    save    <r0,r2>            ; /63/ save regs used by caller
  1038.     tst    do8bit            ; if doing 8-bit prefixing
  1039.     beq    150$            ; and
  1040.     tstb    r1            ; bit_test(ch,200) is true
  1041.     bpl    150$            ; then
  1042.     movb    ebquot    ,(r4)+        ; buffer[i] := eight_bit_quote
  1043.     inc    r3            ; i := succ(i)
  1044.     bicb    #200    ,r1        ; ch := bit_clear(ch,200)
  1045. 150$:    mov    r1    ,r2        ; /63/ ch0_7 := ch
  1046.     bic    #^c<177>,r2        ; ch0_6 := ch0_7 and 177
  1047.     cmpb    r2    ,senpar+p.qctl    ; if ch0_6 = quote (ignoring hi bit)
  1048.     beq    190$            ; /63/ then quote it
  1049.     tst    do8bit            ; if doing 8-bit prefixing
  1050.     beq    160$            ; and
  1051.     cmpb    r2    ,ebquot        ; if ch0_6 == binary_quote
  1052.     beq    190$            ; /63/ then quote it
  1053. 160$:    tst    dorpt            ; if doing repeat compression
  1054.     beq    170$            ; /63/ and
  1055.     cmpb    r2    ,rptquo        ; if ch0_6 == repeat_quote
  1056.     beq    190$            ; /63/ then quote it
  1057. 170$:    mov    r1    ,r0        ; /63/ copy to map char into ctlflgs
  1058.     incb    r0            ; /63/ wrap 377 to 0, others ch=ch+1
  1059.     cmp    r0    ,#41        ; /63/ was char 37..0,377 (now 40..0)?
  1060.     blo    180$            ; /63/ yes, check for quoting enabled
  1061.     sub    #137    ,r0        ; /63/ no, bump 240..200 to 101..41
  1062.     cmp    r0    ,#41        ; /63/ if now < 41 then it's
  1063.     blo    200$            ; /63/ not a control char
  1064.     cmp    r0    ,#101        ; /63/ if now > 101 then it's
  1065.     bhi    200$            ; /63/ not a control char
  1066. 180$:    tstb    ctlflgs(r0)        ; /63/ quote this control char?
  1067.     beq    200$            ; /63/ no, pass it as it is..
  1068.     ctl    r1    ,r1        ; /63/ ch0_7 := ctl(ch0_7)
  1069.     ctl    r2    ,r2        ; /63/ ch0_6 := ctl(ch0_6)
  1070. 190$:    movb    senpar+p.qctl,(r4)+    ; /63/ buffer[i] := quote
  1071.     inc    r3            ; /63/ length := succ(length)
  1072. 200$:    tst    image            ; if image_mode
  1073.     beq    210$            ; then
  1074.     movb    r1    ,(r4)+        ; buffer[i] := ch0_7
  1075.     br    220$            ; else
  1076. 210$:    movb    r2    ,(r4)+        ; buffer[i] := ch0_6
  1077. 220$:    inc    r3            ; length := succ(length)
  1078.     unsave    <r2,r0>            ; /63/ restore caller's registers
  1079.     return
  1080.  
  1081.  
  1082.     .sbttl    Get the next char
  1083.  
  1084. gnc:    tst    r5            ; /63/ where is the next char?
  1085.     beq    10$            ; /63/ get it from a file
  1086.     clr    r0            ; /63/ preset to return success
  1087.     clr    r1            ; /63/ avoid sxt
  1088.     bisb    (r5)+    ,r1        ; /63/ get next char from input buff
  1089.     bne    30$            ; /63/ go add it to stats
  1090.     mov    #er$eof    ,r0        ; /63/ hit a null, flag end of data
  1091.     br    20$            ; /63/ and exit
  1092.  
  1093. 10$:    mov    #lun.in    ,r0        ; copy of file channel number
  1094.     call    getcr0            ; get next char
  1095.     tst    r0            ; did it work?
  1096.     beq    30$            ; ya
  1097. 20$:    sec                ; no, flag an error
  1098.     return
  1099.  
  1100. 30$:    add    #1    ,fileout+2    ; /62/ stats on file data
  1101.     adc    fileout+0        ; /43/ 32. bits
  1102.     clc                ; success  clc here just in case..!
  1103.     return
  1104.  
  1105.  
  1106.     .sbttl    Error message handler
  1107.  
  1108. ;    E R R O R
  1109. ;
  1110. ;    input:      (r5)    = arg count
  1111. ;         2(r5)    = text for message #1
  1112. ;         4(r5)    = and so on, total length not to exceed erbfsiz
  1113.  
  1114. error::    save    <r1,r2,r3,r4,r5>
  1115.     tst    remote            ; if not remote then printm(..)
  1116.     bne    10$            ; we are the remote, send errors
  1117.     call    printm            ; simple
  1118.     tst    linksts            ; /63/ was link running?
  1119.     beq    70$            ; /63/ nope..
  1120.     tst    inprogress        ; /63/ packet exchange in progress?
  1121.     beq    70$            ; /63/ nope..  else send error packet
  1122.  
  1123. 10$:    mov    (r5)+    ,r1        ; message count
  1124.     beq    70$            ; nothing to do
  1125.  
  1126.     sub    #erbfsiz+2,sp        ; remote, allocate a text buffer
  1127.     mov    sp    ,r4        ; and point to it please
  1128.     mov    #erbfsiz,r2        ; /BBS/ init erbfsiz byte counter
  1129.  
  1130. 20$:    mov    (r5)+    ,r3        ; get the next message please
  1131. 30$:    movb    (r3)+    ,@r4        ; now copy it to the buffer until
  1132.     beq    40$            ; we get a null
  1133.     inc    r4            ; bump buffer pointer to next pos
  1134.     sob    r2    ,30$        ; or until we run
  1135.     br    50$            ; out of space to put it
  1136. 40$:    dec    r2            ; ensure sufficient space
  1137.     beq    50$            ; don't overwrite stack!!
  1138.     sob    r1    ,20$        ; and get the next message
  1139. 50$:    clrb    @r4            ; ensure .asciz
  1140.  
  1141.     mov    sp    ,r4        ; all done, send the error packet
  1142.     strlen    r4            ; get the length
  1143.     spack    #msg$error,paknum,r0,r4    ; and send it
  1144.     bit    #log$pa    ,trace        ; /62/ logging packets?
  1145.     beq    60$            ; /62/ nope
  1146.     strlen    r4            ; /62/ ya, get length of it all
  1147.     calls    putrec    ,<r4,r0,#lun.lo> ; /62/ and dump buffer to disk
  1148.     tst    r0            ; /62/ did it work?
  1149.     beq    60$            ; /62/ ya
  1150.     call    logerr            ; /62/ no, go say why not
  1151. 60$:    add    #erbfsiz+2,sp        ; /62/ deallocate the text buffer
  1152. 70$:    unsave    <r5,r4,r3,r2,r1>
  1153.     return
  1154.  
  1155.  
  1156.     .sbttl    Print message if not remote, and copy to logfile
  1157.  
  1158. ;    P R I N T M            ; /62/ major revision
  1159. ;
  1160. ;    input:      (r5)    = arg count
  1161. ;         2(r5)    = text for message #1
  1162. ;         4(r5)    = and so on, total length not to exceed erbfsiz
  1163.  
  1164. printm::save                ; save r0 - r5, inclusive
  1165.     mov    (r5)+    ,r1        ; get the message count
  1166.     beq    100$            ; nothing to do
  1167.  
  1168.     sub    #erbfsiz+2,sp        ; allocate a local text buffer
  1169.     mov    sp    ,r4        ; and a pointer to it
  1170.     mov    #erbfsiz,r2        ; init byte overflow counter
  1171.  
  1172.     cmpb    @(r5)    ,#'?        ; is this an error message?
  1173.     beq    10$            ; ya, skip "Kermit:" prefix
  1174.     cmpb    @(r5)    ,#'%        ; /62/ is this an error message?
  1175.     beq    10$            ; /62/ ya, skip "Kermit:" prefix
  1176.     scan    #':    ,@r5        ; look for a colon indicating a
  1177.     tst    r0            ; prefix string ala "Xyz: "
  1178.     bne    10$            ; found one, don't do 2 headers
  1179.     mov    #pak.01    ,r3        ; stuff in "Kermit: " prefix
  1180.     inc    r1            ; by adding it to the arg count
  1181.     br    20$            ; and jumping in here..
  1182.  
  1183. 10$:    mov    (r5)+    ,r3        ; get the next message please
  1184.     tst    tsxsav            ; TSX?
  1185.     beq    20$            ; no
  1186.     cmpb    (r3)    ,m.tsxr        ; is it the TSX lead-in char?
  1187.     bne    20$            ; no
  1188.     inc    r3            ; ya, skip past it and
  1189.     br    30$            ; don't type this to TT
  1190. 20$:    movb    (r3)+    ,@r4        ; now copy it to the buffer until
  1191.     beq    40$            ; we get an ascii null
  1192. 30$:    inc    r4            ; bump buffer pointer to next position
  1193.     sob    r2    ,20$        ; or until we run
  1194.     br    50$            ; out of space to put it
  1195. 40$:    dec    r2            ; ensure sufficient space
  1196.     beq    50$            ; don't overwrite stack!!
  1197.     sob    r1    ,10$        ; and get the next message
  1198.  
  1199. 50$:    clrb    (r4)            ; ensure .asciz
  1200.     mov    sp    ,r4        ; all done, restore pointer
  1201.  
  1202.     tst    inserv            ; skip TT stuff if a server
  1203.     bne    80$            ; go check for disk logging
  1204.     tst    remote            ; skip if we are the remote
  1205.     bne    80$            ; go check for disk logging
  1206.     tst    xmode            ; if amidst an extended reply
  1207.     bne    60$            ; do a newline for sure..
  1208.     tst    logini            ; need a .newline if this is set
  1209.     beq    70$            ; no, this line is clean
  1210. 60$:    .newline
  1211. 70$:    wrtall    r4            ; dump local buffer to terminal
  1212.     .newline
  1213.     clr    logini            ; may need a logging header
  1214.  
  1215. 80$:    bit    #log$pa    ,trace        ; logging packets?
  1216.     beq    90$            ; nope
  1217.     strlen    r4            ; ya, get length of it all
  1218.     calls    putrec    ,<r4,r0,#lun.lo> ; and dump buffer to disk
  1219.     tst    r0            ; did it work?
  1220.     beq    90$            ; ya
  1221.     call    logerr            ; no, go say why not
  1222. 90$:    add    #erbfsiz+2,sp        ; pop local buffer
  1223. 100$:    unsave
  1224.     return
  1225.  
  1226.  
  1227.     .sbttl    Logfile error handler    ; /62/ all new
  1228.  
  1229. logerr::calls    syserr    ,<r0,#errtxt>    ; enter with r0=whatever_the_error_was
  1230.     .close    #lun.lo            ; save what did make it to logfile..
  1231.     bic    #<log$op!log$al!log$io>,trace ; kill all disk-based debugging
  1232.     mov    #er$lwe    ,r0        ; this is some logfile write error..
  1233.     calls    syserr    ,<r0,#spare1>    ; generate an error message saying so
  1234.     strcat    #spare1    ,#pak.07    ; /62/ now insert a <cr><lf> after it
  1235.     strcat    #spare1    ,#errtxt    ; then include the reported error too
  1236.     tst    inserv            ; skip TT stuff
  1237.     bne    30$            ; if a server
  1238.     tst    remote            ; skip if we
  1239.     bne    30$            ; are the remote
  1240. 10$:    tst    logini            ; need a .newline if this is set
  1241.     beq    20$            ; no, this line is clean
  1242.     .newline
  1243. 20$:    wrtall    #spare1            ; dump local buffer to terminal
  1244.     .newline
  1245.     clr    logini            ; may need a packet cnt logging header
  1246.     return
  1247.  
  1248. 30$:    tst    linksts            ; got a path for an error packet?
  1249.     beq    10$            ; nope, dump it to TT regardless then
  1250.     strlen    #spare1            ; ya, get the length of and
  1251.     spack    #msg$error,paknum,r0,#spare1 ; then send the error message
  1252.     movb    #sta.abo,state        ; /62/ and force the trasnfer to abort
  1253.     return
  1254.  
  1255.  
  1256.     .sbttl    Process retry and sync errors
  1257.  
  1258. m$retr::save    <r0>            ; retry abort
  1259.     bitb    #200    ,recbit        ; /44/ perhaps parity was going?
  1260.     beq    10$            ; /44/ no
  1261.     tst    parity            ; /BBS/ do we know about parity?
  1262.     bne    10$            ; /44/ yes we do, normal abort
  1263.     calls    error    ,<#2,#e$retr,#e$pari> ; /62/ no, mention it now!
  1264.     br    20$            ; /44/ exit
  1265. 10$:    calls    error    ,<#1,#e$retr>    ; send/print the error message
  1266. 20$:    unsave    <r0>
  1267.     return
  1268.  
  1269. m$sync::save    <r0>            ; out of sync
  1270.     calls    error    ,<#1,#e$sync>    ; send/print the error message
  1271.     unsave    <r0>
  1272.     return
  1273.  
  1274.  
  1275.     .sbttl    Compute parity for an outgoing 8-bit link
  1276.  
  1277. ;    This is software parity generation as it allows Kermit to control
  1278. ;    it even on interfaces which don't support it (by setting them for
  1279. ;    8 data bits and no parity).  It was derived from the Pascal RT-11
  1280. ;    Kermit by Phil Murton, and does a table lookup to compute parity.
  1281. ;    For the sake of speed and because some RT-11 systems lack certain
  1282. ;    instructions this method is used at a slight cost in space.
  1283.  
  1284. dopari::save    <r0,r1>            ; /BBS/    somewhat cleaned up..
  1285.     mov    parity    ,r0        ; get the current parity setting
  1286.     beq    10$            ; nothing to do
  1287.     asl    r0            ; word indexing to addresses
  1288.     mov    6(sp)    ,r1        ; get the character to do it to
  1289.     jsr    pc    ,@pardsp(r0)    ; and dispatch as desired
  1290.     mov    r1    ,6(sp)        ; return the character please
  1291. 10$:    unsave    <r1,r0>
  1292.     return
  1293.  
  1294.     .save
  1295.     .psect    $pdata
  1296. pardsp:    .word    0  ,odd.p  ,even.p  ,mark.p  ,spac.p
  1297.     .restore
  1298.  
  1299. mark.p:    bisb    #200    ,r1        ; mark means we are always HIGH
  1300.     return                ; on bit seven
  1301.  
  1302. spac.p:    bicb    #200    ,r1        ; space means we are always LOW
  1303.     return                ; on bit seven
  1304.  
  1305. odd.p:    bic    #^c<177>,r1        ; hose any previous parity
  1306.     tstb    partab(r1)        ; if char's entry in table is <>
  1307.     bne    10$            ; leave parity bit clear
  1308.     bisb    #200    ,r1        ; else set parity bit
  1309. 10$:    return
  1310.  
  1311. even.p:    bic    #^c<177>,r1        ; hose any previous parity
  1312.     tstb    partab(r1)        ; if char's entry in table is 0
  1313.     beq    10$            ; leave parity bit clear
  1314.     bisb    #200    ,r1        ; else set parity bit
  1315. 10$:    return
  1316.  
  1317.     .save
  1318.     .psect    $pdata
  1319. partab:    .byte    0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0  ; first 16 ascii characters
  1320.     .byte    1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
  1321.     .byte    1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
  1322.     .byte    0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
  1323.     .byte    1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1
  1324.     .byte    0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
  1325.     .byte    0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
  1326.     .byte    1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1  ; last 16 characters (to 177)
  1327.     .restore
  1328.  
  1329.     .end
  1330.