home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / mscp98.asm < prev    next >
Assembly Source File  |  2020-01-01  |  58KB  |  1,743 lines

  1.     NAME    msscom
  2. ; File MSSCOM.ASM
  3.     include mssdef.h
  4. ;       Copyright (C) 1982,1991, Trustees of Columbia University in the
  5. ;       City of New York.  Permission is granted to any individual or
  6. ;       institution to use, copy, or redistribute this software as long as
  7. ;       it is not sold for profit and this copyright notice is retained.
  8. ; Edit history:
  9. ; 2 March 1991 version 3.10
  10. ; Last edit 23 Jan 1991
  11.  
  12.     public    spack, rpack, sleep, spause, bufclr, pakptr, bufrel
  13.     public    makebuf, getbuf, pakdup, chkwind, firstfree, windused
  14.     public    rpacket, windlow, chkparflg
  15.  
  16. stat_suc equ    0        ; success
  17. stat_tmo equ    1        ; timeout
  18. stat_chk equ    2        ; checksum mismatch
  19. stat_ptl equ    4        ; packet too long
  20. stat_int equ    8        ; user interrupt
  21. stat_eol equ    10h        ; eol char seen
  22. stat_bad equ    80h        ; packet is bad (premature EOL)
  23.  
  24. data    segment    public 'data'
  25.     extrn    flags:byte, trans:byte, fsta:word, ssta:word, fmtdsp:byte
  26.     extrn    pktnum:byte, portval:word, denyflg:word
  27.  
  28. parmsk    db    0ffh        ; parity mask (0FFH for 8bit data path) [umd]
  29. badpflag db    0        ; flag to say have shown bad parity message
  30. spmes    db    'Spack: $'
  31. rpmes     db    'Rpack: $'
  32. crlf    db      cr,lf,'$'
  33. msgstl    db    'Internal Error: send packet is too long',0,'$'
  34. msgtmo    db    '<Timeout>',cr,lf,'$'
  35. msgbad    db    '<Crunched packet>',cr,lf,'$'
  36. msgecho    db    '<Echo of sent packet>',cr,lf,'$'
  37. msgbadsnd db    cr,lf,'<Error sending packet bytes>',cr,lf,'$'
  38. msgbadpare db    'Unexpected Parity from host! Changing Parity to EVEN'
  39.     db    cr,lf,0
  40. msgbadparo db    'Unexpected Parity from host! Changing Parity to ODD'
  41.     db    cr,lf,0
  42. msgbadparm db    'Unexpected Parity from host! Changing Parity to MARK'
  43.     db    cr,lf,0
  44. tmp    db    0
  45. spause    db    0        ; # millisec to wait before sending pkt
  46. timeval    db    0        ; active receive timeout value, seconds
  47. prvtyp  db      0        ; Type of last packet sent
  48. chkparflg db    0        ; non-zero to check parity on received pkts
  49. prevchar db    0        ; previous char from comms line (for ^C exit)
  50. lentyp    db    0        ; packet length type, 3, 0, 1
  51. debflg    db    0        ; debug display, send/receive flag
  52. timeit    db    0        ; arm timeout counter
  53. flowon    db    0        ; xon or null, flow-on value
  54.                 ; sliding windows data structures
  55. windlow    db    0        ; lower border of window
  56. windused db    0        ; number of window slots in use
  57. prolog  db    10 dup (0)    ; prolog: SOH, LEN, SEQ, TYPE, xlen,...,null
  58. epilog    db    30 dup (0)    ; epilog: checksum, eol, handshake + null term
  59. rbuf    db    128 dup (0)    ; static packet buffer for replies
  60.     even
  61. bufnum    dw    0        ; number of buffers available now
  62. buflist dw    maxwind dup (0) ; pointers to packet structures in pktlist
  63. bufuse    dw    maxwind dup (0) ; in-use flag (0 = not in use)
  64. pktlist    pktinfo maxwind dup (<>) ; pktinfo structured members (private)
  65. bufbuf    db    maxpack+((3*maxwind)/2) dup (0) ; Data buffer for packets
  66. rpacket    pktinfo <offset rbuf,0,length rbuf,0,0> ; reply pktinfo
  67.     even
  68. rtemp    dw    0        ; address of pktinfo structure for rpack
  69. stemp    dw    0        ; address of pktinfo structure for spack
  70. linecnt    dw    0        ; debug line width counter
  71. pktptr  dw    0        ; position in receive packet
  72. chksum    dw    0        ; running checksum (two char)
  73. chrcnt    dw    0        ; number of bytes in data field of a packet
  74. spkcnt    dw    0        ; number of bytes sent in this packet
  75. rpkcnt    dw    0        ; number of bytes received in this packet
  76. status    dw    0        ; status of packet receiver (0 = ok)
  77. deblen    dw    0        ; length of current debug buffer
  78. fairflg    dw    0        ; fairness flag, for console/port reads
  79. time     dw    2 dup (0)    ; Sleep, when we should timeout
  80. rptim    db    4 dup (0)    ; read packet timeout slots
  81. sixzero    dw    60        ; for div operation in rec packet timeouts
  82. ninefive dw    95        ; for mult/div with long packets
  83. temp    dw    0
  84. data    ends
  85.  
  86. code    segment    public 'code'
  87.     extrn    prtchr:near, outchr:near, isdev:near
  88.     extrn    sppos:near, ermsg:near, clearl:near, rppos:near
  89.     extrn    pktcpt:near, strlen:near, pcwait:near
  90.  
  91.     assume     cs:code, ds:data, es:nothing
  92. prtchr1    proc    far        ; near-far interface routines for code1 seg
  93.     call    prtchr
  94.     ret
  95. prtchr1    endp
  96. outchr1    proc    far
  97.     call    outchr
  98.     ret
  99. outchr1    endp
  100. isdev1    proc    far
  101.     call    isdev
  102.     ret
  103. isdev1    endp
  104. rppos1    proc    far
  105.     call    rppos
  106.     ret
  107. rppos1    endp
  108. sppos1    proc    far
  109.     call    sppos
  110.     ret
  111. sppos1    endp
  112. ermsg1    proc    far
  113.     call    ermsg
  114.     ret
  115. ermsg1    endp
  116. clearl1    proc    far
  117.     call    clearl
  118.     ret
  119. clearl1    endp
  120. pktcpt1    proc    far
  121.     call    pktcpt
  122.     ret
  123. pktcpt1    endp
  124. strlen1    proc    far
  125.     call    strlen
  126.     ret
  127. strlen1    endp
  128. pcwait1    proc    far
  129.     call    pcwait
  130.     ret
  131. pcwait1    endp
  132. code    ends
  133.  
  134. code1    segment    public    'code'
  135.     assume     cs:code1, ds:data, es:nothing
  136.  
  137. ; Send_Packet
  138. ; This routine assembles a packet from the arguments given and sends it
  139. ; to the host.
  140. ;
  141. ; Expects the following:
  142. ;    SI = pointer to pktinfo structure, as
  143. ;    [SI].PKTYPE - Packet type letter
  144. ;    [SI].SEQNUM - Packet sequence number
  145. ;    [SI].DATLEN - Number of data characters
  146. ;    [SI].DATADR - Address of data field for packet
  147. ; Returns: carry clear if success, carry set if failure.
  148. ; Packet construction areas:
  149. ;     Prolog (8 bytes)            Data     null  Epilog
  150. ;+----------------------------------------+---------------+---------------+
  151. ;| SOH,LEN,SEQ,TYPE,Xlen(2-3),Xlen chksum | packet's data | chksum,EOL,HS |
  152. ;+----------------------------------------+---------------+---------------+
  153. ; where Xlen is 2 byte (Long) or 3 byte (Extra Long) count of bytes to follow.
  154. ;
  155. SPACK    PROC    FAR
  156.     mov    stemp,si    ; save pkt pointer
  157.     mov    ah,[si].pktype
  158.     mov    prvtyp,ah    ; remember packet type
  159.     mov    spkcnt,0    ; number of bytes sent in this packet
  160.     add    fsta.pspkt,1    ; statistics, count a packet being sent
  161.     adc    fsta.pspkt+2,0    ;  ripple carry
  162.     add    ssta.pspkt,1    ; statistics, count a packet being sent
  163.     adc    ssta.pspkt+2,0    ;  ripple carry
  164.     mov    al,spause    ; wait spause milliseconds before sending pkt
  165.     or    al,al        ; zero?
  166.     jz    spac1        ; z = yes
  167.     xor    ah,ah
  168.     call    pcwait1        ;   to let other side get ready
  169. spac1:    mov    cl,trans.spad    ; get the number of padding chars
  170.     xor    ch,ch
  171.     jcxz    spac4        ; z = none
  172.     xor    al,al
  173.     xchg    al,trans.sdbl    ; doubling char, stash and clear it
  174.     push    ax
  175.     mov    ah,trans.spadch    ; get padding char
  176. spac2:    call    spkout        ; send padding char
  177.     jnc    spac3        ; nc = success
  178.     ret            ; failed
  179. spac3:    loop    spac2
  180.     pop    ax        ; recover doubling char
  181.     xchg    trans.sdbl,al
  182.  
  183. spac4:    mov    bx,offset prolog ; start with these guys
  184.     mov    pktptr,bx
  185.     call    snddeb        ; do debug display (while it's still our turn)
  186.     mov    bx,offset prolog ; start with these guys
  187.     mov    pktptr,bx
  188.     push    es
  189.     push    ds
  190.     pop    es
  191.     cld
  192.     mov    cx,length prolog
  193.     mov    di,offset prolog
  194.     xor    al,al
  195.     rep    stosb
  196.     mov    cx,length epilog
  197.     mov    di,offset epilog
  198.     rep    stosb
  199.     pop    es
  200.     mov    al,trans.ssoh    ; get the start of header char
  201.     mov    prolog,al    ; put SOH in the packet
  202.     mov    si,stemp    ; address of send pktinfo
  203.     mov    al,[si].seqnum    ; SEQ
  204.     add    al,20h        ; ascii bias
  205.     mov    prolog+2,al    ; store SEQ in packet
  206.     xor    ah,ah
  207.     mov    chksum,ax    ; start checksum
  208.     mov    al,prvtyp    ; TYPE
  209.     mov    prolog+3,al    ; store TYPE
  210.     add    chksum,ax    ; add to checksum
  211. ;
  212. ; packet length type is directly governed here by length of header plus data
  213. ; field, [si].datlen, plus chksum: regular <= 94, long <= 9024, else X long.
  214. ;
  215.     mov    ax,[si].datlen    ; DATA length
  216.     add    ax,2        ; add SEQ, TYPE lengths
  217.     add    al,trans.chklen    ; add checksum length at the end
  218.     adc    ah,0        ; propagate carry, yields overall new length
  219.     cmp    ax,[si].datsize    ; too big?
  220.     jle    spac14        ; le = ok
  221.     push    dx        ; tell user an internal error has occurred
  222.     mov    dx,offset msgstl ; packet is too long
  223.     call    ermsg1        ; display message on error line
  224.     call    captdol        ; put into packet log
  225.     pop    dx
  226.     stc
  227.     ret            ; return bad
  228.  
  229. spac14:    mov    lentyp,3    ; assume regular packet
  230.     cmp    ax,94        ; longer than a regular?
  231.     ja    spac15        ; a = use Long
  232.     add    al,20h        ; convert length to ascii
  233.     mov    prolog+1,al    ; store LEN
  234.     xor    ah,ah
  235.     add    chksum,ax    ; add LEN to checksum
  236.     mov    bx,offset prolog+4 ; look at data field
  237.     jmp    spac19        ; do regular
  238.  
  239.                 ; use Long packets (type 0)
  240. spac15:    sub    ax,2        ; deduct SEQ and TYPE from above = data+chksum
  241.     mov    lentyp,0    ; assume type 0 packet
  242.     cmp    ax,(95*95-1)    ; longest type 0 Long packet (9024)
  243.     jbe    spac16        ; be = type 0
  244.     mov    lentyp,1    ; type 1 packet, Extra Long
  245. spac16:    mov    cl,lentyp    ; add new LEN field to checksum
  246.     add    cl,20h        ; ascii bias, tochar()
  247.     xor    ch,ch
  248.     add    chksum,cx    ; add to running checksum
  249.     mov    prolog+1,cl    ; put LEN into packet
  250.     mov    bx,offset prolog+4
  251.     mov    cx,1        ; a counter
  252.     xor    dx,dx        ; high order numerator of length
  253. spac17:    div    ninefive    ; divide ax by 95. quo = ax, rem = dx
  254.     push    dx        ; push remainder
  255.     inc    cx        ; count push depth
  256.     cmp    ax,95        ; quotient >= 95?
  257.     jae    spac17        ; ae = yes, recurse
  258.     push    ax        ; push for pop below
  259. spac18:    pop    ax        ; get a digit
  260.     add    al,20h        ; apply tochar()
  261.     mov    [bx],al        ; store in data field
  262.     add    chksum,ax    ; accumulate checksum for header
  263.     inc    bx        ; point to next data field byte
  264.     mov    byte ptr[bx],0    ; insert terminator
  265.     loop    spac18        ; get the rest
  266.                 ;
  267.     mov    ax,chksum    ; current checksum
  268.     shl    ax,1        ; put two highest bits of al into ah
  269.     shl    ax,1
  270.     and    ah,3        ; want just those two bits
  271.     shr    al,1        ; put al back in place
  272.     shr    al,1
  273.     add    al,ah        ; add two high bits to earlier checksum
  274.     and    al,03fh        ; chop to lower 6 bits (mod 64)
  275.     add    al,20h        ; apply tochar()
  276.     mov    [bx],al        ; store that in length's header checksum
  277.     inc    bx
  278.     mov    byte ptr [bx],0 ; terminator to prolog field
  279.     xor    ah,ah
  280.     add    chksum,ax    ; add that byte to running checksum
  281.                 ; end of inserting Long pkt info
  282.  
  283. spac19:    mov    cx,bx        ; where we stopped+1
  284.     mov    bx,offset prolog ; place where prolog section starts
  285.     sub    cx,bx
  286.     jcxz    spac22        ; nothing
  287. spac20:    mov    ah,[bx]        ; prolog part
  288.     or    ah,ah        ; at the end?
  289.     jz    spac22        ; z = yes
  290.     inc    bx
  291.     call    spkout        ; send byte to serial port
  292.     jnc    spac21        ; nc = good send
  293.     jmp    spac28        ; bad send
  294. spac21:    loop    spac20        ; do all prolog parts
  295. spac22:    mov    pktptr,offset prolog ; starting point for deblin, end = [bx-1]
  296.     call    deblin        ; show debug info for prolog
  297.     mov    si,stemp    ; address of pktinfo
  298.     mov    bx,[si].datadr    ; select from given data buffer
  299.     mov    pktptr,bx    ; start here with next deblin
  300.     mov    dx,[si].datlen    ; get the number of data bytes in packet
  301. spac23:    or    dx,dx        ; any data chars remaining?
  302.     jle    spac25        ; le = no, finish up
  303.     mov    al,[bx]        ; get a data char
  304.     inc    bx        ; point to next char [umd]
  305. spac24:    xor    ah,ah
  306.     add    chksum,ax    ; add the char to the checksum [umd]
  307.     and    chksum,0fffh    ; keep only low order 12 bits
  308.     mov    ah,al        ; put char in ah where spkout wants it
  309.     dec    dx        ; say sending one character
  310.     call    spkout        ; send it
  311.     jnc    spac23        ; nc = success, get more data chars
  312.     jmp    spac28        ; bad send
  313.  
  314. spac25:    mov    byte ptr [bx],0    ; terminator of data field
  315.     call    deblin        ; show debug display of data field
  316.     mov    bx,offset epilog ; area for epilog
  317.     mov    pktptr,bx    ; where to start last of debug display
  318.     mov    cx,chksum
  319.     cmp    trans.chklen,2    ; what kind of checksum are we using?
  320.     je    spac27        ; e = 2 characters
  321.     jg    spac26        ; g = 3 characters
  322.     mov    ah,cl        ; 1 char: get the character total
  323.     mov    ch,cl        ; save here too (need 'cl' for shift)
  324.     and    ah,0C0H        ; turn off all but the two high order bits
  325.     mov    cl,6
  326.     shr    ah,cl        ; shift them into the low order position
  327.     mov    cl,ch
  328.     add    ah,cl        ; add it to the old bits
  329.     and    ah,3FH        ; turn off the two high order bits.  (MOD 64)
  330.     add    ah,' '        ; add a space so the number is printable
  331.     mov    [bx],ah        ; put in the packet
  332.     inc    bx        ; point to next char
  333.     call    spkout        ; send it
  334.     jnc    spac30        ; add EOL char
  335.     jmp    spac28        ; bad send
  336. spac26: mov    byte ptr[bx],0    ; null, to determine end of buffer
  337.     push    bx        ; don't lose our place
  338.     mov    bx,offset prolog+1 ; first checksummed char, skip SOH
  339.     xor    dx,dx        ; initial CRC value is 0
  340.     call    crcclc        ; calculate the CRC of prolog part, to cx
  341.     mov    si,stemp    ; address of pktinfo
  342.     mov    bx,[si].datadr    ; address of data
  343.     push    bx        ; save address
  344.     add    bx,[si].datlen    ; byte beyond data
  345.     mov    byte ptr [bx],0    ; null terminator for CRC
  346.     pop    bx        ; recover address of data
  347.     mov    dx,cx        ; first part of CRC returned in cx
  348.     call    crcclc        ; do CRC of data, using current CRC in dx
  349.     pop    bx        ; recover place to store more debug info
  350.     push    cx        ; save the crc
  351.     mov    ax,cx        ; manipulate it here
  352.     and    ax,0F000H    ; get 4 highest bits
  353.     mov    cl,4
  354.     shr    ah,cl        ; shift over 4 bits
  355.     add    ah,' '        ; make printable
  356.     mov    [bx],ah        ; add to buffer
  357.     inc    bx
  358.     pop    cx        ; get back checksum value
  359.     call    spkout        ; send it
  360.     jnc    spac27
  361.     jmp    short spac28    ; bad send
  362. spac27:    push    cx        ; save it for now
  363.     and    cx,0FC0H    ; get bits 6-11
  364.     mov    ax,cx
  365.     mov    cl,6
  366.     shr    ax,cl        ; shift them bits over
  367.     add    al,' '        ; make printable
  368.     mov    [bx],al        ; add to buffer
  369.     inc    bx
  370.     mov    ah,al
  371.     call    spkout        ; send it
  372.     pop    cx        ; get back the original
  373.     jc    spac28        ; c = bad send
  374.     and    cx,003FH    ; get bits 0-5
  375.     add    cl,' '        ; make printable
  376.     mov    [bx],cl        ; add to buffer
  377.     inc    bx
  378.     mov    ah,cl
  379.     call    spkout        ; send it
  380.     jnc    spac30
  381. spac28:    call    deblin        ; show debug info so far before exiting
  382.     mov    dx,offset msgbadsnd ; say sending error in log
  383.     call    captdol
  384.     mov    si,stemp    ; restore pkt pointer
  385.     stc            ; carry set for failure
  386.     RET            ; bad send, do ret to caller of spack
  387.  
  388. spac30:    mov    ah,trans.seol    ; get the EOL the other host wants
  389.     mov    [bx],ah        ; put eol
  390.     inc    bx
  391.     call    deblin        ; do debug display (while it's still our turn)
  392.     test    flags.debug,logpkt ; In debug mode?
  393.     jnz    spac31        ; nz = yes
  394.     test    flags.capflg,logpkt ; log packets?
  395.     jz    spac32        ; z = no
  396. spac31:    cmp    linecnt,0    ; anything on current line?
  397.     je    spac32        ; e = no
  398.     mov    dx,offset crlf    ; finish line with cr/lf
  399.     call    captdol        ;  to log file
  400. spac32:    mov    ah,trans.seol    ; recover EOL
  401.     call    spkout        ; send it
  402.     jnc    spac33
  403.     stc            ; bad send
  404.     ret            ; return in error state
  405.  
  406. spac33:    mov    ax,spkcnt    ; number of bytes sent in this packet
  407.     add    fsta.psbyte,ax    ; file total bytes sent
  408.     adc    fsta.psbyte+2,0    ; propagate carry to high word
  409.     add    ssta.psbyte,ax    ; for session
  410.     adc    ssta.psbyte+2,0
  411.     call    chkcon        ; check console for user interrupts
  412.     mov    si,stemp    ; restore pkt pointer
  413.     clc            ; carry clear for success
  414.     ret            ; return successfully
  415. SPACK    ENDP 
  416.  
  417. spkout:    cmp    ah,trans.sdbl    ; double this char?
  418.     jne    spkou1        ; ne = no
  419.     call    spkou1        ; do it once here and again via fall through
  420.     jnc    spkou1        ;  but again only if no failure
  421.     ret            ; return failure
  422. spkou1:    push    ax        ; send char in ah out the serial port
  423.     push    bx        ; return carry clear if success
  424.     push    cx
  425.     push    dx
  426.     mov    tmp,1        ; retry counter
  427. spkour:    call    outchr1        ; serial port transmitter procedure
  428.     jc    spkoux        ; c = bad send, retry
  429.     inc    spkcnt        ; count number of bytes sent in this packet
  430.     pop    dx
  431.     pop    cx
  432.     pop    bx
  433.     pop    ax
  434.     clc            ; carry    clear for good send
  435.     ret
  436. spkoux:    cmp    tmp,5        ; done 5 attempts on this char?
  437.     jge    spkoux1        ; ge = yes, fail the sending
  438.     inc    tmp
  439.     push    ax
  440.     mov    ax,10        ; wait 10 milliseconds
  441.     call    pcwait1
  442.     pop    ax
  443.     jmp    short spkour    ; retry
  444. spkoux1:pop    dx        ; failed to send char
  445.     pop    cx
  446.     pop    bx
  447.     pop    ax
  448.     stc            ; set carry for bad send
  449.     ret
  450.      
  451. ; Calculate the CRC of the null-terminated string whose address is in BX.
  452. ; Returns the CRC in CX.  Destroys BX and AX.
  453. ; The CRC is based on the SDLC polynomial: x**16 + x**12 + x**5 + 1.
  454. ; By Edgar Butt  28 Oct 1987 [ebb].
  455. ; Enter with initial CRC in DX (normally 0).
  456. crcclc: push    dx
  457.     mov    cl,4            ; load shift count
  458. crc0:   mov    ah,[bx]            ; get the next char of the string
  459.         or    ah,ah            ; if null, then we're done
  460.         jz    crc1            ; z = null, stop
  461.         inc    bx
  462.         xor    dl,ah            ; XOR input with lo order byte of CRC
  463.         mov    ah,dl            ; copy it
  464.         shl    ah,cl            ; shift copy
  465.         xor    ah,dl            ; XOR to get quotient byte in ah
  466.         mov    dl,dh            ; high byte of CRC becomes low byte
  467.         mov    dh,ah            ; initialize high byte with quotient
  468.         xor    al,al
  469.         shr    ax,cl            ; shift quotient byte
  470.         xor    dl,ah            ; XOR (part of) it with CRC
  471.         shr    ax,1            ; shift it again
  472.         xor    dx,ax            ; XOR it again to finish up
  473.         jmp    short crc0
  474. crc1:   mov    cx,dx            ; return CRC in CX
  475.         pop    dx
  476.         ret
  477.  
  478. ; Receive_Packet
  479. ; This routine waits for a packet arrive from the host. Two Control-C's in a
  480. ; row from the comms line will cause a Control-C interruption exit.
  481. ; Returns
  482. ;    SI = pointer to pktinfo structure, as
  483. ;    [SI].SEQNUM - Packet sequence number
  484. ;    [SI].DATLEN - Number of data characters
  485. ;    [SI].DATADR - Address of data field for packet
  486. ; Returns AH -  packet type (letter code)
  487. ; Returns: carry clear if success, carry set if failure.
  488. ; Packet construction areas:
  489. ;     Prolog (8 bytes+2 nulls)    null    Data    null  Epilog   null
  490. ;+----------------------------------------+---------------+---------------+
  491. ;| SOH,LEN,SEQ,TYPE,Xlen(2-3),Xlen chksum | packet's data | chksum,EOL,HS |
  492. ;+----------------------------------------+---------------+---------------+
  493. ; where Xlen is 2 byte (Long) or 3 byte (Extra Long) count of bytes to follow.
  494.  
  495. RPACK    PROC    FAR
  496.     mov    rtemp,si        ; save pkt structure address
  497.     xor    ax,ax            ; get a zero
  498.     mov    debflg,al        ; say debugging display not setup
  499.     mov    fairflg,ax        ; set fairness flag
  500.     mov    badpflag,al        ; bad parity flag, clear it
  501.     mov    prevchar,al        ; clear previous recv'd char area
  502.     mov    [si].pktype,'T'        ; assume 'T' type packet (timeout)
  503.     mov    bx,[si].datadr        ; caller's data buffer
  504.     mov    pktptr,bx        ; debug buffer pointer for new stuff
  505.     mov    [si].datlen,ax        ; init to empty buffer
  506.     mov    cx,[si].datsize        ; length of that buffer, for debugger
  507.     mov    deblen,cx
  508.     mov    word ptr [bx],ax    ; clear storage areas (asciiz)
  509.     mov    word ptr prolog,ax
  510.     mov    word ptr epilog,ax
  511.     mov    cl,trans.stime        ; time to wait for start of packet
  512.     mov    timeval,cl        ; local timer value, seconds
  513.     mov    status,stat_suc        ; assume success
  514.     mov    rpkcnt,ax        ; number of bytes rcvd in packet
  515.     push    bx
  516.     mov    parmsk,0ffh        ; parity mask, assume 8 bit data
  517.     mov    bx,portval
  518.     mov    ax,[bx].flowc        ; flow control
  519.     mov    flowon,al        ; xon or null
  520.     xor    ax,ax
  521.     cmp    [bx].parflg,parnon    ; parity is none?
  522.     pop    bx
  523.     je    rpack0a            ; e = none
  524.     mov    parmsk,7fh        ; else strip parity (8th) bit
  525.     jmp    rpack0a
  526.  
  527.                     ; get here with unexpected char
  528. rpack0:    test    status,stat_tmo        ; timeout get us here?
  529.     jnz    rpack0f            ; nz = yes, no new char to record
  530.     xor    ah,ah
  531.     mov    [bx],ax            ; store 8 bit char in buffer
  532.     inc    bx            ; advance buffer pointer
  533. rpack0f:push    ax            ; save around this work
  534.     cmp    debflg,0        ; started debugging display yet?
  535.     jne    rpack0d            ; ne = yes
  536.     call    rcvdeb            ; setup receive debug display
  537. rpack0d:call    deblin            ; debug, show chars received thus far
  538.     mov    bx,rtemp        ; pktinfo address
  539.     mov    [bx].datlen,0        ; say no data yet
  540.     mov    [bx].seqnum,0ffh    ; illegal value
  541.     mov    [bx].pktype,0        ; illegal value
  542.     mov    ax,[bx].datsize     ; length of that buffer, for debugger
  543.     mov    deblen,ax
  544.     mov    bx,[bx].datadr        ; data field address, reuse for prolog
  545.     mov    pktptr,bx        ; debug buffer pointer for new stuff
  546.     xor    ax,ax
  547.     mov    word ptr [bx],ax     ; clear the data field
  548.     mov    word ptr prolog,ax    ; clear prolog field
  549.     mov    word ptr epilog,ax    ; clear epilog field
  550.     mov    rpkcnt,ax        ; count of chars
  551.     pop    ax            ; recover unexpected char
  552.     test    status,stat_int        ; interrupted?
  553.     jz    rpack0e            ; z = no
  554.     jmp    rpack60            ; yes, exit now
  555. rpack0e:mov    status,stat_suc        ; assume success
  556.     and    al,7fh            ; strip high bit
  557.     cmp    al,trans.rsoh        ; was unexpected char the SOH?
  558.     je    rpack1            ; e = yes, get LEN char
  559.  
  560. rpack0a:call    inchr            ; get a character. SOH
  561.     jnc    rpack0b            ; nc = got one
  562.                 ; c=failure (eol, timeout, user intervention)
  563.     test    status,stat_eol        ; hit eol from prev packet?
  564.     jnz    rpack0            ; nz = yes, restart
  565.     jmp    rpack60            ; timeout or user intervention
  566.  
  567. rpack0b:mov    ah,al            ; copy the char
  568.     and    ah,7fh            ; strip any parity bit, regardless
  569.     cmp    ah,trans.rsoh        ; start of header char?
  570.     je    rpack0c            ; e = yes, SOH
  571.     jmp    rpack0            ; ne = no, go until it is
  572. rpack0c:xor    ah,ah            ; clear the terminator byte
  573.     mov    [bx],ax            ; store 8 bit char in buffer
  574.     inc    bx            ; advance buffer pointer
  575. rpack1:    mov    timeval,1        ; reduce local timer value to 1 second
  576.     call    inchr            ; get a character. LEN
  577.     jc    rpack1a            ; failure
  578.     mov    [bx],al            ; store LEN in buffer
  579.     and    al,7fh            ; strip any parity bit
  580.     cmp    al,trans.rsoh        ; start of header char?
  581.     jne    rpack1b            ; ne = no
  582. rpack1a:jmp    rpack0            ; yes, start over (common jmp point)
  583. rpack1b:inc    bx
  584.     mov    chksum,ax        ; start the checksum
  585.     sub    al,20h            ; unchar(LEN) to binary
  586.     jnc    rpack1e            ; nc = legal (printable)
  587.     mov    status,stat_ptl        ; set bad length status
  588.     jmp    rpack40            ; and quit
  589. rpack1e:mov    si,rtemp
  590.     mov    [si].datlen,ax        ; save the data count (byte)
  591.     call    inchr            ; get a character. SEQ
  592.     jc    rpack1a            ; c = failure
  593.     mov    [bx],al            ; store SEQ in buffer
  594.     inc    bx
  595.     and    al,7fh            ; strip any parity bit
  596.     cmp    al,trans.rsoh        ; SOH?
  597.     je    rpack1a            ; e = yes, then go start over
  598.     add    chksum,ax
  599.     sub    al,' '            ; get the real packet number
  600.     jnc    rpack1f            ; nc = no overflow
  601.     mov    status,stat_ptl        ; say bad status
  602.     jmp    rpack40            ; and exit now
  603. rpack1f:mov    si,rtemp
  604.     mov    [si].seqnum,al        ; save the packet number. SEQ
  605.     call    inchr            ; get a character. TYPE
  606.     jc    rpack1a            ; c = failure
  607.     mov    [bx],al            ; store TYPE in buffer
  608.     inc    bx
  609.     and    al,7fh            ; strip any parity bit
  610.     cmp    al,trans.rsoh        ; SOH?
  611.     je    rpack1a            ; e = yes, then go start over
  612.     mov    [si].pktype,al        ; save the message type
  613.     add    chksum,ax        ; add it to the checksum
  614.     call    parchk            ; check parity on protocol characters
  615.     call    getlen        ; get complicated data length (reg, lp, elp)
  616.                 ; into [si].datlen and kind into byte lentyp. carry set if error
  617.     jnc    rpack1c            ; nc = packet is ok so far
  618.     jmp    rpack40            ; failure
  619. rpack1c:
  620. ; Start of change.
  621. ; Now determine block check type for this packet.  Here we violate the layered
  622. ; nature of the protocol by inspecting the packet type in order to detect when
  623. ; the two sides get out of sync.  Two heuristics allow us to resync here:
  624. ;   a. I and S packets always has a type 1 checksum.
  625. ;   b. A NAK never contains data, so its block check type is seqnum1.
  626.     mov    si,rtemp        ; pktinfo address
  627.     mov    ax,[si].datlen        ; length of packet information
  628.     mov    cl,[si].pktype        ; packet type byte itself
  629.     cmp    cl,'S'            ; "S" packet?
  630.     jne    rpk0            ; ne = no
  631.     mov    trans.chklen,1        ; S packets use one byte checksums
  632.     jmp    short rpk3
  633. rpk0:    cmp    cl,'I'            ; I packets are like S packets
  634.     jne    rpk1
  635.     mov    trans.chklen,1        ; I packets use one byte checksums
  636.     jmp    short rpk3
  637. rpk1:    cmp    cl,'N'            ; NAK?
  638.     jne    rpk3            ; ne = no
  639.     cmp    ax,1            ; NAK, get length of data + chklen
  640.     jb    rpk1a            ; b = impossible length
  641.     cmp    ax,3            ; longest NAK (3 char checksum)
  642.     jbe    rpk2            ; be = possible
  643. rpk1a:    or    status,stat_ptl        ; status = bad length
  644.     jmp    rpack40            ; return on impossible length
  645. rpk2:    mov    trans.chklen,al        ; remainder must be checksum type for NAK
  646. rpk3:    sub    al,trans.chklen        ; minus checksum length, for all pkts
  647.     sbb    ah,0            ; propagate borrow
  648.     mov    [si].datlen,ax        ; store apparent length of data field
  649. ; End of change.
  650. ; now, for long packets we start the real data (after the extended byte
  651. ; count 3 or 4 bytes) at offset data and thus the checksumming starts
  652. ; such packets a few bytes earlier.
  653.     push    si
  654.     push    di
  655.     mov    si,rtemp        ; pktinfo address
  656.     mov    si,[si].datadr        ; data field address
  657.     mov    di,offset prolog    ; where to store
  658.     mov    cx,4            ; number of bytes to move, reg pkts
  659.     cmp    lentyp,0        ; long packets?
  660.     jne    rpk5            ; ne = no
  661.     mov    cx,7            ; seven bytes mark...type, xl,xl,xlchk
  662.     jmp    short rpk7
  663. rpk5:    cmp    lentyp,1        ; extra long packets?
  664.     jne    rpk7            ; ne = no
  665.     mov    cx,8            ; extra long packets
  666. rpk7:    push    es            ; save es
  667.     push    ds
  668.     pop    es            ; set es to data segment
  669.     cld                ; move forward
  670.     rep    movsb            ; move the protocol header, cx times
  671.     mov    byte ptr [di],0     ; null terminator
  672.     pop    es
  673.     pop    di
  674.     pop    si
  675.  
  676.     mov    si,rtemp
  677.     push    si
  678.     mov    si,[si].datadr
  679.     mov    word ptr [si],0        ; clear data field for debugging
  680.     pop    si
  681.     mov    dx,[si].datlen        ; length of data field, excl LP header
  682.     mov    chrcnt,dx
  683.     cmp    dx,[si].datsize        ; material longer than data buffer?
  684.     ja    rpk8b            ; a = yes, give up
  685.     mov    dx,trans.rlong        ; longest packet we should receive
  686.     sub    dl,trans.chklen        ; minus checksum length
  687.     sbb    dh,0            ; propagate borrow
  688.     cmp    dx,chrcnt        ; is data too long?
  689.     jae    rpk8c            ; ae = not too big
  690.     or    status,stat_ptl        ; failure status, packet too long
  691. rpk8b:    jmp    rpack40            ; too big, quit now
  692. rpk8c:    mov    bx,[si].datadr        ; point to the data buffer
  693.     mov    pktptr,bx        ; start of buffer for debugging
  694.     mov    dx,[si].datsize     ; length of that buffer, for debugger
  695.     mov    deblen,dx        ; keep here
  696.     mov    word ptr [bx],0        ; clear start of that buffer
  697.                     ; get DATA field characters
  698. rpack2:    cmp    chrcnt,0        ; any chars expected?
  699.     jle    rpack3            ; le = no, go do checksum
  700.     call    inchr            ; get a character into al. DATA
  701.     jc    rpak2c            ; c = Control-C, timeout, eol
  702.     mov    [bx],ax            ; put char into buffer, with null
  703.     inc    bx            ; point to next free slot
  704.     cmp    al,trans.rsoh        ; start of header char?
  705.     jne    rpak2b            ; ne = no
  706.     jmp    rpack7            ; yes, then go start over
  707. rpak2b:    add    chksum,ax        ; inchr clears AH
  708.     dec    chrcnt            ; one less char expected
  709.     jmp    short rpack2        ; get another data character
  710. rpak2c:    jmp    rpack40            ; Control-C, timeout, EOL
  711.  
  712. rpack3:    mov    byte ptr[bx],0        ; terminate data field
  713.     and    chksum,0fffh    ; keep only lower 12 bits of current checksum
  714.     call    inchr            ; start Checksum bytes
  715.     jc    rpack3b            ; failed
  716.     mov    ah,al
  717.     and    ah,7fh            ; strip high bit
  718.     cmp    ah,trans.rsoh        ; start of header char?
  719.     jne    rpack3a            ; ne = no
  720.     jmp    rpack7            ; yes, then go start over
  721. rpack3a:mov    bx,offset epilog    ; record debugging in epilog buffer
  722.     mov    pktptr,bx        ; start of that buffer, for debug
  723.     mov    deblen,length epilog    ; length of that buffer
  724.     xor    ah,ah
  725.     mov    [bx],ax            ; store checksum
  726.     inc    bx            ; point at next slot
  727.     sub    al,' '            ; unchar() back to binary
  728.     mov    cx,chksum        ; current checksum
  729.     cmp    trans.chklen,2        ; which checksum length is in use?
  730.     je    rpack5            ; e = Two character checksum
  731.     jg    rpack4            ; g = Three char CRC, else one char
  732.     shl    cx,1            ; put two highest digits of al into ah
  733.     shl    cx,1
  734.     and    ch,3            ; want just those two bits
  735.     shr    cl,1            ; put al back in place
  736.     shr    cl,1
  737.     add    cl,ch            ;add two high bits to earlier checksum
  738.     and    cl,03fh            ; chop to lower 6 bits (mod 64)
  739.     cmp    cl,al        ; computed vs received checksum byte (binary)
  740.     je    rpack3b            ; e = equal, so finish up
  741.     or    status,stat_chk        ; say checksum failure
  742. rpack3b:jmp    rpack40
  743.  
  744. rpack7:    jmp    rpack0            ; for the jump out of range
  745.  
  746. rpack4:    mov    tmp,al            ; save value from packet here
  747.     push    bx            ; three character CRC
  748.     mov    cx,[bx-1]        ; save checksum char and next
  749.     mov    temp,cx
  750.     mov    bx,offset prolog+1    ; where data for CRC is, skipping SOH
  751.     xor    dx,dx            ; initial CRC is zero
  752.     call    crcclc            ; calculate the CRC and put into CX
  753.     mov    bx,rtemp
  754.     mov    bx,[bx].datadr        ; data field address
  755.     mov    dx,cx            ; previous CRC
  756.     call    crcclc            ; final CRC is in CX
  757.     pop    bx
  758.     mov    ax,temp
  759.     mov    [bx-1],ax        ; restore char pair from above
  760.     mov    ah,ch            ; cx = 16 bit binary CRC of rcv'd data
  761.     and    ah,0f0h            ; manipulate it here
  762.     shr    ah,1
  763.     shr    ah,1            ; get 4 highest bits
  764.     shr    ah,1
  765.     shr    ah,1            ; shift right 4 bits
  766.     cmp    ah,tmp            ; is what we got == calculated?
  767.     je    rpack4a            ; e = yes
  768.     or    status,stat_chk        ; checksum failure
  769. rpack4a:call    inchr            ; get next character of checksum
  770.     jc    rpack40            ; c = failed
  771.     mov    [bx],ax            ; put into buffer for debug
  772.     inc    bx
  773.     and    al,7fh            ; strip high bit
  774.     cmp    al,trans.rsoh        ; SOH?
  775.     je    rpack7            ; e = yes
  776.     sub    al,' '            ; get back real value
  777. rpack5:    mov    tmp,al            ; save here for now
  778.     push    cx            ; two character checksum
  779.     and    cx,0FC0H        ; get bits 6-11
  780.     mov    ax,cx
  781.     mov    cl,6
  782.     shr    ax,cl            ; shift bits
  783.     pop    cx            ; get back the original
  784.     cmp    al,tmp            ; equal?
  785.     je    rpack5a            ; e = yes
  786.     or    status,stat_chk        ; checksum failure
  787. rpack5a:call    inchr            ; get last character of checksum
  788.     jc    rpack40            ; c = failed
  789.     mov    [bx],ax            ; put into buffer for debug
  790.     inc    bx
  791.     and    al,7fh            ; strip high bit
  792.     cmp    al,trans.rsoh        ; SOH?
  793.     je    rpack7            ; e = yes
  794.     sub    al,' '            ; get back real value    
  795.     and    cx,003FH        ; get bits 0-5
  796.     cmp    al,cl            ; do the last chars match?
  797.     je    rpack40            ; e = yes
  798.     or    status,stat_chk        ; say checksum failure
  799.  
  800. rpack40:mov    byte ptr [bx],0        ; terminate current buffer
  801.     test    status,stat_tmo        ; timeout?
  802.     jz    rpack41            ; z = no
  803.     jmp    rpack60            ; nz = yes
  804. rpack41:test    status,stat_eol        ; premature eol?
  805.     jz    rpack42            ; z = no
  806.     or    status,stat_bad        ; say bad packet overall
  807.     mov    bx,offset epilog     ; start debugging with epilog buffer
  808.     mov    pktptr,bx
  809.     mov    deblen,length epilog    ; length of that buffer
  810.     mov    [bx],ax            ; put it into buffer for debug
  811.     inc    bx
  812.     jmp    short rpack45        ; now try for handshake
  813.  
  814. rpack42:push    bx
  815.     sub    bx,pktptr    ; next char slot - starting address, debugging
  816.     cmp    bx,deblen        ; at length of active debug buffer?
  817.     pop    bx
  818.     jb    rpack43            ; b = no
  819.     call    rdebug            ; yes, dump what we have
  820.     mov    bx,offset epilog    ; and start again with epilog buffer
  821.     mov    pktptr,bx
  822.     mov    deblen,length epilog    ; length of that buffer
  823. rpack43:call    inchr            ; get eol char
  824.     jnc    rpack43a        ; nc = got regular character
  825.     test    status,stat_int        ; interrupted?
  826.     jnz    rpack60            ; nz = yes
  827.     test    status,stat_tmo        ; timeout?
  828.     jnz    rpack43b        ; nz = yes, no char
  829. rpack43a:mov    [bx],ax            ; put into buffer for debug
  830.     inc    bx
  831. rpack43b:and    status,not stat_tmo    ; ignore timeouts on EOL character
  832.     test    status,stat_eol        ; eol char?
  833.     jnz    rpack44            ; nz = yes, got the EOL char
  834.     and    al,7fh            ; strip high bit
  835.     cmp    al,trans.rsoh        ; soh already?
  836.     jne    rpack44            ; ne = no
  837.     jmp    rpack0            ; yes, do debug display and start over
  838.  
  839. rpack44:and    status,not stat_eol     ; desired eol is not an error
  840. rpack45:push    bx            ; test for line turn char
  841.     mov    bx,portval        ;   if doing handshaking
  842.     mov    ah,[bx].hands        ; get desired handshake char
  843.     cmp    [bx].hndflg,0        ; doing half duplex handshaking?
  844.     pop    bx
  845.     je    rpack60            ; e = no
  846.     mov    tmp,ah            ; keep it here
  847.     call    inchr            ; get handshake char
  848.     jnc    rpack45a        ; nc = regular character
  849.     test    status,stat_eol        ; EOL char?
  850.     jnz    rpack45a        ; nz = yes
  851.     jmp    short rpack48        ; timeout or user intervention
  852. rpack45a:and    status,not stat_eol    ; ignore unexpected eol status here
  853.     mov    si,rtemp
  854.     mov    cx,[si].datsize        ; length of receive buffer
  855.     add    cx,[si].datadr        ; starting address of the buffer
  856.     cmp    bx,cx            ; filled buffer yet?
  857.     jae    rpack46            ; ae = yes
  858.     mov    [bx],ax            ; put into buffer for debug
  859.     inc    bx
  860. rpack46:and    al,7fh            ; strip high bit
  861.     cmp    al,trans.rsoh        ; soh already?
  862.     jne    rpack47            ; ne = no
  863.     jmp    rpack0            ; yes, do debug display and start over
  864. rpack47:cmp    al,tmp            ; compare received char with handshake
  865.     jne    rpack45        ; ne = not handshake, try again til timeout
  866. rpack48:and    status,not stat_tmo    ; ignore timeouts on handshake char
  867.  
  868.                     ; Perform logging and debugging now
  869. rpack60:call    rdebug            ; helper procedure
  870.     call    chkcon            ; check console for user interrupt
  871.     test    status,stat_tmo        ; did a timeout get us here?
  872.     jz    rpack61            ; z = no
  873.     mov    si,rtemp
  874.     mov    [si].pktype,'T'        ; yes, say 'T' type packet (timeout)
  875.     test    flags.capflg,logpkt     ; log packets?
  876.     jz    rpack61            ; z = no
  877.     mov    dx,offset msgtmo     ; say timeout in log
  878.     call    captdol
  879. rpack61:test    status,not stat_tmo    ; crunched packet?
  880.     jz    rpack62            ; z = no
  881.     test    flags.capflg,logpkt     ; log packets?
  882.     jz    rpack62            ; z = no
  883.     mov    dx,offset msgbad     ; say crunched pkt in log
  884.     call    captdol
  885.  
  886. rpack62:mov    ax,rpkcnt        ; number of bytes received in packet
  887.     add    fsta.prbyte,ax        ; file total received bytes
  888.     adc    fsta.prbyte+2,0        ; propagate carry to high word
  889.     add    ssta.prbyte,ax        ; session total received bytes
  890.     adc    ssta.prbyte+2,0        ; propagate carry to high word
  891.     add    fsta.prpkt,1        ; file received packet
  892.     adc    fsta.prpkt+2,0        ;  ripple carry
  893.     add    ssta.prpkt,1        ; session received packet
  894.     adc    ssta.prpkt+2,0
  895.     mov    si,rtemp        ; restore pkt pointer
  896.     mov    ah,[si].pktype        ; return packet type in ah
  897.         cmp    ah,prvtyp        ; packet type same as last sent?
  898.     jne    rpack64            ; ne = no
  899.     test    flags.capflg,logpkt     ; log packets?
  900.     jz    rpack63            ; z = no
  901.     mov    dx,offset msgecho     ; say echo in log
  902.     call    captdol
  903. rpack63:test    status,stat_int        ; interrupted?
  904.     jnz    rpack64            ; nz = yes, exit now
  905.     jmp    rpack            ; discard echoed packet and read again
  906.  
  907. rpack64:cmp    status,stat_suc        ; successful so far?
  908.     jne    rpack65            ; ne = no
  909.     cmp    chkparflg,0        ; do parity checking?
  910.     je    rpack64a        ; e = no
  911.     mov    chkparflg,0        ; do only once
  912.     test    badpflag,80h        ; get parity error flagging bit
  913.     jz    rpack64a        ; z = no parity error
  914.     mov    bx,portval
  915.     mov    cl,badpflag        ; get new parity plus flagging bit
  916.     and    cl,7fh            ; strip flagging bit
  917.     mov    [bx].parflg,cl        ; force new parity
  918. rpack64a:clc                ; carry clear for success
  919.     ret
  920. rpack65:stc                ; carry set for failure
  921.     ret                ; failure exit
  922. RPACK    ENDP
  923.  
  924. rdebug    proc    near
  925.     cmp    debflg,0        ; setup debug display yet?
  926.     jne    rdebu1            ; ne = yes
  927.     call    rcvdeb            ; setup display
  928. rdebu1:    test    flags.debug,logpkt    ; in debug mode?
  929.     jnz    rdebu2            ; nz = yes
  930.     test    flags.capflg,logpkt    ; log packets?
  931.     jz    rdebu5            ; z = no
  932. rdebu2:    mov    dx,offset prolog    ; do prolog section
  933.     mov    pktptr,dx
  934.     mov    bx,dx
  935.     call    strlen1            ; get length of prolog section
  936.     jcxz    rdebu3            ; z = empty, try next section
  937.     add    bx,cx            ; point off end
  938.     call    deblin            ; do debug display
  939.     mov    prolog,0        ; clear prolog field
  940. rdebu3:    mov    bx,rtemp        ; do data section
  941.     mov    bx,[bx].datadr
  942.     mov    dx,bx
  943.     mov    pktptr,bx
  944.     call    strlen1            ; get length of data section
  945.     jcxz    rdebu4            ; z = empty, try next section
  946.     add    bx,cx            ; point off end
  947.     call    deblin            ; do debug display
  948. rdebu4:    mov    bx,offset epilog    ; do epilog section
  949.     mov    pktptr,bx
  950.     mov    dx,bx
  951.     call    strlen1            ; get length of epilog section
  952.     jcxz    rdebu5            ; z = empty
  953.     add    bx,cx            ; point off end
  954.     call    deblin            ; do debug display
  955.     mov    epilog,0        ; clear epilog field
  956. rdebu5:    test    flags.debug,logpkt    ; In debug mode?
  957.     jnz    rdebu6            ; nz = yes
  958.     test    flags.capflg,logpkt    ; log packets?
  959.     jz    rdebu7            ; z = no
  960. rdebu6:    cmp    linecnt,0        ; anything on current line?
  961.     je    rdebu7            ; e = no
  962.     mov    dx,offset crlf        ; finish line with cr/lf
  963.     call    captdol            ;  to log file
  964. rdebu7:    ret
  965. rdebug    endp
  966.  
  967. ; Check Console (keyboard). Return carry setif "action" chars: cr for forced
  968. ; timeout, Control-E for force out Error packet, Control-C for quit work now.
  969. ; Return carry clear on Control-X and Control-Z as these are acted upon by
  970. ; higher layers. Consume and ignore anything else.
  971. chkcon:    call    isdev1        ; is stdin a device and not a disk file?
  972.     jnc    chkco5        ; nc = no, a disk file so do not read here
  973.     mov    dl,0ffh
  974.     mov    ah,dconio        ; read console
  975.     int    dos
  976.     jz    chkco5            ; z = nothing there
  977.     and    al,1fh            ; make char a control code
  978.     cmp    al,CR            ; carriage return?
  979.     je    chkco3            ; e = yes, simulate timeout
  980.     cmp    al,'C'-40h        ; Control-C?
  981.     je    chkco1            ; e = yes
  982.     cmp    al,'E'-40h        ; Control-E?
  983.     je    chkco1            ; e = yes
  984.     cmp    al,'X'-40h        ; Control-X?
  985.     je    chkco4            ; e = yes
  986.     cmp    al,'Z'-40h        ; Control-Z?
  987.     je    chkco4        ; record it, take no immmediate action here
  988.     cmp    al,'Q'-40h        ; Control-Q?
  989.     je    chkco6            ; e = yes
  990.     or    al,al            ; scan code being returned?
  991.     jnz    chkco5            ; nz = no, ignore ascii char
  992.     mov    ah,dconio        ; read and discard second byte
  993.     mov    dl,0ffh
  994.     int    dos
  995.     jmp    short chkco5        ; else unknown, ignore
  996. chkco1:    or    al,40h            ; make Control-C-E printable
  997.     mov    flags.cxzflg,al        ; remember what we saw
  998. chkco2:    or    status,stat_int        ; interrupted
  999.     stc
  1000.     ret                ; act now
  1001. chkco3:    or    status,stat_tmo        ; CR simulates timeout
  1002.     stc
  1003.     ret                ; act now
  1004. chkco4:    or    al,40h            ; make control-X-Z printable
  1005.     mov    flags.cxzflg,al        ; put into flags
  1006.     clc                ; do not act on them here
  1007.     ret
  1008. chkco5:    cmp    flags.cxzflg,'C'    ; control-C intercepted elsewhere?
  1009.     je    chkco2            ; e = yes
  1010.     clc                ; else say no immediate action needed
  1011.     ret
  1012. chkco6:    xchg    ah,al            ; put Control-Q in AH for transmission
  1013.     call    spkout            ; send it now
  1014.     jmp    short chkco5
  1015.  
  1016. getlen    proc    near        ; compute packet length for short & long types
  1017.                 ; returns length in [si].datlen and
  1018.                 ; length type (0, 1, 3) in local byte lentyp
  1019.                 ; returns length of  data + checksum
  1020.     mov     si,rtemp
  1021.     mov    ax,[si].datlen    ; get LEN byte value
  1022.     and    ax,7fh        ; clear unused high byte and parity bit
  1023.  
  1024.     cmp    al,3        ; regular packet has 3 or larger here
  1025.     jb    getln1        ; b = long packet
  1026.     sub    [si].datlen,2    ; minus SEQ and TYPE = DATA + CHKSUM
  1027.     mov    lentyp,3    ; store assumed length type (3 = regular)
  1028.     clc            ; clear carry for success
  1029.     ret
  1030.  
  1031. getln1:    push    cx        ; counter for number of length bytes
  1032.     mov    lentyp,0    ; store assumed length type 0 (long)
  1033.     mov    cx,2        ; two base-95 digits
  1034.     or    al,al        ; is this a type 0 (long packet)?
  1035.     jz    getln2        ; z = yes, go find & check length data
  1036.     mov    lentyp,1    ; store length type (1 = extra long)
  1037.     inc    cx        ; three base 95 digits
  1038.     cmp    al,1        ; is this a type 1 (extra long packet)?
  1039.     je    getln2        ; e = yes, go find & check length data
  1040.     pop    cx
  1041.     or    status,stat_ptl    ; say packet too long (an unknown len code)
  1042.     stc            ; set carry bit to say error
  1043.     ret
  1044. getln2:                ; chk header chksum and recover binary length
  1045.     push    dx        ; save working reg
  1046.     xor    ax,ax        ; clear length accumulator, low part
  1047.     mov    [si].datlen,ax    ; clear final length too
  1048. getln3:    xor    dx,dx        ; ditto, high part
  1049.     mov    ax,[si].datlen    ; length to date
  1050.     mul    ninefive    ; multiply accumulation (in ax) by 95
  1051.     mov    [si].datlen,ax    ; save results
  1052.     push    cx
  1053.     call    inchr        ; read another serial port char into al
  1054.     pop    cx
  1055.     jc    getln4        ; c = failure
  1056.     xor    ah,ah
  1057.     mov    [bx],al        ; store in buffer
  1058.     inc    bx
  1059.     add    chksum,ax
  1060.     sub    al,20h        ; subtract space, apply unchar()
  1061.     mov    si,rtemp
  1062.     add    [si].datlen,ax    ; add to overall length count
  1063.     loop    getln3        ; cx preset earlier for type 0 or type 1
  1064.     mov    dx,chksum    ; get running checksum
  1065.     shl    dx,1        ; get two high order bits into dh
  1066.     shl    dx,1
  1067.     and    dh,3        ; want just these two bits
  1068.     shr    dl,1        ; put low order part back
  1069.     shr    dl,1
  1070.     add    dl,dh        ; add low order byte to two high order bits
  1071.     and    dl,03fh        ; chop to lower 6 bits (mod 64)
  1072.     add    dl,20h        ; apply tochar()
  1073.     push    dx
  1074.     call    inchr        ; read another serial port char
  1075.     pop    dx
  1076.     jc    getln4        ; c = failure
  1077.     xor    ah,ah
  1078.     mov    [bx],al        ; store in buf for debug
  1079.     inc    bx
  1080.     add    chksum,ax
  1081.     cmp    dl,al        ; our vs their checksum, same?
  1082.     je    getln5        ; e = checksums match, success
  1083. getln4:    or    status,stat_chk    ; checksum failure
  1084.     pop    dx        ; unsave regs (preserves flags)
  1085.     pop    cx
  1086.     stc            ; else return carry set for error
  1087.     ret
  1088. getln5:    pop    dx        ; unsave regs (preserves flags)
  1089.     pop    cx
  1090.     clc            ; clear carry (say success)
  1091.     ret
  1092. getlen    endp
  1093.  
  1094. ; Get char from serial port into al, with timeout and console check.
  1095. ; Return carry set if timeout or console char or EOL seen,
  1096. ; return carry clear and char in AL for other characters.
  1097. ; Sets status of stat_eol if EOL seen.
  1098. ; Fairflg allows occassional reads from console before looking at serial port.
  1099. inchr    proc    near
  1100.     mov    timeit,0    ; reset timeout flag (do each char separately)
  1101.     push    bx        ; save a reg
  1102.     cmp    fairflg,maxpack/4 ; look at console first every now and then
  1103.     jbe    inchr1        ; be = not console's turn yet
  1104.     mov    fairflg,0    ; reset fairness flag for next time
  1105.     call    chkcon        ; check console
  1106.     jnc    inchr1        ; nc = nothing to interrupt us
  1107.     pop    bx        ; clean stack
  1108.     ret            ; return failure for interruption
  1109.  
  1110. inchr1:    call    prtchr1        ; read a serial port character
  1111.     jc    inchr2        ; c = nothing there
  1112.     pop    bx        ; here with char in al from port
  1113.     mov    ah,al        ; copy char to temp place AH
  1114.     and    ah,7fh        ; strip parity bit from work copy
  1115.     and    al,parmsk    ; apply 7/8 bit parity mask
  1116.     or    ah,ah        ; null char?
  1117.     jz    inchr        ; ignore the null, read another char
  1118.     cmp    ah,del        ; ascii del byte?
  1119.     je    inchr        ; e = yes, ignore it too
  1120.     inc    rpkcnt        ; count received byte
  1121.     cmp    al,trans.rign    ; char in al to be ignored?
  1122.     je    inchr        ; e = yes, do so
  1123.     cmp    ah,'C'-40h    ; Control-C from comms line?
  1124.     jne    inchr6        ; ne = no
  1125.     cmp    ah,prevchar    ; was previous char also Control-C?
  1126.     jne    inchr6        ; ne = no
  1127.     cmp    ah,trans.rsoh    ; could this also be an SOH?
  1128.     je    inchr6        ; e = yes, do not exit
  1129.     cmp    ah,trans.reol    ; could this also be an EOL?
  1130.     je    inchr6        ; e = yes
  1131.     test    denyflg,finflg    ; is FIN enabled?
  1132.     jnz    inchr6        ; nz = no, ignore server exit cmd
  1133.     mov    flags.cxzflg,'C'; set Control-C flag
  1134.     or    status,stat_int+stat_eol ; say interrupted and End of Line
  1135.     mov    al,ah        ; use non-parity version
  1136.     xor    ah,ah        ; always return with high byte clear
  1137.     stc            ; exit failure
  1138.     ret
  1139. inchr6:    mov    prevchar,ah    ; remember current as previous char
  1140.     cmp    ah,trans.reol    ; eol char we want?
  1141.     je    inchr7        ; e = yes, ret with carry set
  1142.     xor    ah,ah        ; always return with high byte clear
  1143.     clc            ; char is in al
  1144.     ret
  1145. inchr7:    or    status,stat_eol    ; set status appropriately
  1146.     mov    al,ah        ; use non-parity version
  1147.     xor    ah,ah        ; always return with high byte clear
  1148.     stc            ; set carry to say eol seen
  1149.     ret            ; and return qualified failure
  1150.     
  1151. inchr2:    call    chkcon        ; check console
  1152.     jnc    inchr2a        ; nc = nothing to interrupt us
  1153.     pop    bx        ; clean stack
  1154.     ret            ; return failure for interruption
  1155.  
  1156. inchr2a:cmp    flags.timflg,0    ; are timeouts turned off?
  1157.     je    inchr1        ; e = yes, just check for more input
  1158.     cmp    trans.stime,0    ; doing time outs?
  1159.     jne    inchr2b        ; ne = yes
  1160.     jmp    inchr1        ; go check for more input
  1161. inchr2b:push    cx        ; save regs
  1162.     push    dx        ; Stolen from Script code
  1163.     cmp    timeit,0    ; have we gotten time of day for first fail?
  1164.     jne    inchr4        ; ne = yes, just compare times
  1165.     mov    ah,gettim    ; get DOS time of day
  1166.     int    dos        ; ch = hh, cl = mm, dh = ss, dl = 0.01 sec
  1167.     xchg    ch,cl        ; get ordering of low byte = hours, etc
  1168.     mov    word ptr rptim,cx ; hours and minutes
  1169.     xchg    dh,dl
  1170.     mov    word ptr rptim+2,dx ; seconds and fraction
  1171.     mov    bl,timeval    ; our desired timeout interval (seconds)
  1172.     xor    bh,bh        ; one byte's worth
  1173.     mov    temp,bx        ; work area
  1174.     mov    bx,2           ; start with seconds field
  1175. inchr3: mov    ax,temp        ; desired timeout interval, working copy
  1176.     add    al,rptim[bx]    ; add current tod digit interval
  1177.     adc    ah,0
  1178.     xor    dx,dx        ; clear high order part thereof
  1179.     div    sixzero        ; compute number of minutes or hours
  1180.     mov    temp,ax        ; quotient, for next time around
  1181.     mov    rptim[bx],dl    ; put normalized remainder in timeout tod
  1182.     dec    bx        ; look at next higher order time field
  1183.     or    bx,bx        ; done all time fields?
  1184.     jge    inchr3        ; ge = no
  1185.     cmp    rptim[0],24    ; normalize hours
  1186.     jl    inchr3a        ; l = not 24 hours or greater
  1187.     sub    rptim[0],24    ; discard part over 24 hours
  1188. inchr3a:mov    timeit,1    ; say have tod of timeout
  1189.  
  1190. inchr4:    mov    ah,gettim    ; compare present tod versus timeout tod
  1191.     int    dos        ; get the time of day
  1192.     sub    ch,rptim    ; hours difference, ch = (now - timeout)
  1193.     je    inchr4b        ; e = same, check mmss.s
  1194.     jl    inchr4d        ; l = we are early
  1195.     cmp    ch,12        ; hours difference, large or small?
  1196.     jge    inchr4d        ; ge = we are early
  1197.     jl    inchr4c        ; l = we are late, say timeout
  1198. inchr4b:cmp    cl,rptim+1    ; minutes, hours match
  1199.     jb    inchr4d        ; b = we are early
  1200.     ja    inchr4c        ; a = we are late
  1201.     cmp    dh,rptim+2    ; seconds, hours and minutes match
  1202.     jb    inchr4d        ; b = we are early
  1203.     ja    inchr4c        ; a = we are late
  1204.     cmp    dl,rptim+3    ; hundredths of seconds, hhmmss match
  1205.     jbe    inchr4d        ; be = we are early
  1206. inchr4c:or    status,stat_tmo    ; say timeout
  1207. ;    cmp    flowon,0    ; using xon/xoff flow control?
  1208. ;    je    inchr4e        ; e = no
  1209. ;    mov    ah,flowon    ; send host an xon in case it's stuck
  1210. ;    call    outchr1        ;   with a stray xoff not from us
  1211. inchr4e:pop    dx
  1212.     pop    cx
  1213.     pop    bx
  1214.     stc            ; set carry bit
  1215.     ret            ; failure
  1216. inchr4d:pop    dx
  1217.     pop    cx
  1218.     jmp    inchr1        ; not timed out yet
  1219. inchr    endp
  1220.  
  1221.  
  1222. ; sleep for the # of seconds in al
  1223. ; Preserve all regs. Added console input forced timeout 21 March 1987 [jrd]
  1224. sleep    proc    far
  1225.     push    ax
  1226.     push    cx
  1227.     push    dx
  1228.     push    ax        ; save argument
  1229.     mov    ah,gettim    ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
  1230.     int    dos        ; get current time
  1231.     pop    ax        ; restore desired # of seconds
  1232.     add    dh,al        ; add # of seconds
  1233. sleep1:    cmp    dh,60        ; too big for seconds?
  1234.     jb    sleep2        ; no, keep going
  1235.     sub    dh,60        ; yes, subtract a minute's overflow
  1236.     inc    cl        ; and add one to minutes field
  1237.     cmp    cl,60        ; did minutes overflow?
  1238.     jb    sleep1        ; no, check seconds again
  1239.     sub    cl,60        ; else take away an hour's overflow
  1240.     inc    ch        ; add it back in hours field
  1241.     jmp    short sleep1    ; and keep checking
  1242. sleep2:    mov    time,cx        ; store desired ending time,  hh,mm
  1243.     mov    time+2,dx    ; ss, .s
  1244. sleep3:    call    chkcon        ; check console for user timeout override
  1245.     jc    short sleep5    ; c = have override
  1246.     mov    ah,gettim    ; get time
  1247.     int    dos        ; from dos
  1248.     sub    ch,byte ptr time+1 ; hours difference, ch = (now - timeout)
  1249.     je    sleep4        ; e = hours match, check mmss.s
  1250.     jl    sleep3        ; l = we are early
  1251.     cmp    ch,12        ; hours difference, large or small?
  1252.     jge    sleep3        ; ge = we are early
  1253.     jl    sleep5        ; l = we are late, exit now
  1254. sleep4:    cmp    cl,byte ptr time ; check minutes, hours match
  1255.     jb    sleep3        ; b = we are early
  1256.     ja    sleep5        ; a = over limit, time to exit
  1257.     cmp    dx,time+2    ; check seconds and fraction, hhmm match
  1258.     jb    sleep3        ; b = we are early
  1259. sleep5:    pop    dx
  1260.     pop    cx
  1261.     pop    ax
  1262.     ret
  1263. sleep    endp
  1264.                 ; Packet Debug display routines
  1265. rcvdeb:    test    flags.debug,logpkt ; In debug mode?
  1266.     jnz    rcvde1        ; nz = yes
  1267.     test    flags.capflg,logpkt ; log packets?
  1268.     jnz    rcvde1        ; nz = yes
  1269.     ret            ; no
  1270. rcvde1:    mov    debflg,'R'    ; say receiving
  1271.     jmp    short deb1
  1272.  
  1273. snddeb:    test    flags.debug,logpkt ; In debug mode?
  1274.     jnz    sndde1        ; nz = yes
  1275.     test    flags.capflg,logpkt ; log packets?
  1276.     jnz    sndde1        ; yes
  1277.     ret            ; no
  1278. sndde1:    mov    debflg,'S'    ; say sending
  1279.  
  1280. deb1:    push    ax        ; Debug. Packet display
  1281.     push    bx
  1282.     push    cx        ; save some regs
  1283.     push    dx
  1284.     push    di
  1285.     test    flags.debug,logpkt    ; is debug active (vs just logging)?
  1286.     jz    deb1d        ; z = no, just logging
  1287.     cmp    fmtdsp,0    ; non-formatted display?
  1288.     je    deb1d        ; e = yes, skip extra line clearing
  1289.     cmp    debflg,'R'    ; receiving?
  1290.     je    deb1a        ; e = yes
  1291.     call    sppos1        ; spack: cursor position
  1292.     jmp    short deb1b
  1293. deb1a:    call    rppos1        ; rpack: cursor position
  1294. deb1b:    call    clearl1        ; clear the line
  1295.         mov    dx,offset crlf
  1296.         mov    ah,prstr    ; display
  1297.         int    dos
  1298.         call    clearl1        ; clear debug line and line beneath
  1299.     cmp    debflg,'R'    ; receiving?
  1300.     je    deb1c        ; e = yes
  1301.     call    sppos1        ; reposition cursor for spack:
  1302.     jmp    short deb1d
  1303. deb1c:    call    rppos1        ; reposition cursor for rpack:
  1304. deb1d:    mov    dx,offset spmes    ; spack: message
  1305.     cmp    debflg,'R'
  1306.     jne    deb2        ; ne = sending
  1307.     mov    dx,offset rpmes    ; rpack: message
  1308. deb2:    call    captdol        ; record dollar terminated string in Log file
  1309.     mov    linecnt,7    ; number of columns used so far
  1310.     pop    di
  1311.     pop    dx
  1312.     pop    cx
  1313.     pop    bx
  1314.     pop    ax
  1315.     ret
  1316.  
  1317. ; Display/log packet chars processed so far.
  1318. ; Displays chars from pktptr to bx-1, both are pointers.
  1319. ; Enter with bx = offset of next new char. All registers preserved
  1320. deblin:    test    flags.debug,logpkt ; In debug mode?
  1321.     jnz    debln0        ; nz = yes
  1322.     test    flags.capflg,logpkt ; log packets?
  1323.     jnz    debln0        ; nz = yes
  1324.     ret            ; else    nothing to do
  1325. debln0:    push    cx
  1326.     push    dx
  1327.     push    di
  1328.     mov    di,pktptr    ; starting place for debug analysis
  1329.     mov    cx,bx        ; place for next new char
  1330.     sub    cx,di        ; minus where we start = number chars to do
  1331.     or    cx,cx
  1332.     jle    debln5        ; le = nothing to do
  1333. debln2:
  1334.     push    cx        ; save loop counter
  1335.     cmp    linecnt,70
  1336.          jb    debln3        ; b = not yet, get next data char
  1337.     mov    dx,offset crlf    ; break line with cr/lf
  1338.     call    captdol        ; and in log file
  1339.     mov    linecnt,0    ; setup for next line
  1340. debln3:    mov    dl,[di]        ; get char
  1341.     test    dl,80h        ; high bit set?
  1342.     jz    debln3b        ; z = no
  1343.     push    dx        ; save char in dl
  1344.     mov    dl,7eh        ; show tilde char for high bit set
  1345.     call    captchr        ; record in Log file
  1346.     inc    linecnt        ; count displayed column
  1347.     cmp    linecnt,70    ; exhausted line count yet?
  1348.     jb    debln3a        ; b = not yet
  1349.     mov    dx,offset crlf    ; break line with cr/lf
  1350.     call    captdol        ; and in log file
  1351.     mov    linecnt,0    ; setup for next line
  1352. debln3a:pop    dx
  1353.     and    dl,7fh        ; get lower seven bits here
  1354. debln3b:cmp    dl,' '        ; control char?
  1355.     jae    debln4        ; ae = no
  1356.     add    dl,40h        ; uncontrollify the char
  1357.     push    dx        ; save char in dl
  1358.     mov    dl,5eh        ; show caret before control code
  1359.     call    captchr        ; record in Log file
  1360.     inc    linecnt        ; count displayed column
  1361.     cmp    linecnt,70    ; exhausted line count yet?
  1362.     jb    debln3c        ; b = not yet
  1363.     mov    dx,offset crlf    ; break line with cr/lf
  1364.     call    captdol        ; and in log file
  1365.     mov    linecnt,0    ; setup for next line
  1366. debln3c:pop    dx        ; recover char in dl
  1367.  
  1368. debln4:    call    captchr        ; record char in dl in the log file
  1369.     inc    di        ; done with this char, point to next
  1370.     inc    linecnt        ; one more column used on screen
  1371.     pop    cx        ; recover loop counter
  1372.     loop    debln2        ; get next data char
  1373. debln5:    pop    di
  1374.     pop    dx
  1375.     pop    cx
  1376.     ret
  1377.  
  1378.  
  1379. captdol    proc    near        ; write dollar sign terminated string in dx
  1380.                 ; to the capture file (Log file).
  1381.     push    ax        ; save regs
  1382.     push    si
  1383.     mov    si,dx        ; point to start of string
  1384.     cld
  1385. captdo1:lodsb            ; get a byte into al
  1386.     cmp    al,'$'        ; at the end yet?
  1387.     je    captdo3        ; e = yes
  1388.     or    al,al        ; asciiz?
  1389.     jz    captdo3        ; z = yes, this is also the end
  1390.     mov    dl,al
  1391.     test    flags.debug,logpkt ; debug display active?
  1392.     jz    captdo2        ; z = no
  1393.     mov    ah,conout
  1394.     int    dos        ; display char in dl
  1395. captdo2:test    flags.capflg,logpkt ; logging active?
  1396.     jz    captdo1        ; z = no
  1397.     mov    al,dl        ; where pktcpt wants it
  1398.     call    pktcpt1        ; record the char, pktcpt is in msster.asm
  1399.     jmp    short captdo1    ; repeat until dollar sign is encountered
  1400. captdo3:pop    si
  1401.     pop    ax
  1402.     ret
  1403. captdol    endp
  1404.  
  1405. captchr    proc    near        ; record char in dl into the Log file
  1406.     push    ax
  1407.     test    flags.debug,logpkt ; debug display active?
  1408.     jz    captch1        ; z = no
  1409.     mov    ah,conout
  1410.     int    dos        ; display char in dl
  1411. captch1:test    flags.capflg,logpkt ; logging active?
  1412.     jz    captch2        ; z = no
  1413.     mov    al,dl        ; where pktcpt wants it
  1414.     call    pktcpt1        ; record the char, pktcpt is in msster.asm
  1415. captch2:pop    ax
  1416.     ret
  1417. captchr    endp
  1418.  
  1419. parchk    proc    near            ; check parity of pkt prolog chars
  1420.     cmp    chkparflg,0        ; ok to check parity?
  1421.     jne    parchk0            ; ne = yes
  1422.     ret
  1423. parchk0:push    ax
  1424.     push    bx
  1425.     push    cx
  1426.     push    dx
  1427.     mov    bx,pktptr        ; where packet prolog is stored now
  1428.     mov    ax,[bx]            ; first two prolog chars
  1429.     or    ax,[bx+2]        ; next two
  1430.     test    ax,8080h        ; parity bit set?
  1431.     jz    parchk7            ; z = no
  1432.     mov    parmsk,7fh        ; set parity mask for 7 bits
  1433.     cmp    badpflag,0        ; said bad parity once this packet?
  1434.     jne    parchk7            ; ne = yes
  1435.     mov    cx,4            ; do all four protocol characters
  1436.     xor    dx,dx            ; dl=even parity cntr, dh=odd parity
  1437. parchk1:mov    al,[bx]            ; get a char
  1438.     inc    bx            ; point to next char
  1439.     or    al,al            ; sense parity
  1440.     jpo    parchk2            ; po = odd parity
  1441.     inc    dl            ; count even parity
  1442.     jmp    short parchk3
  1443. parchk2:inc    dh            ; count odd parity
  1444. parchk3:loop    parchk1            ; do all four chars
  1445.     cmp    dl,4            ; got four even parity chars?
  1446.     jne    parchk4            ; ne = no
  1447.     mov    badpflag,parevn+80h    ; say even parity and flagging bit
  1448.     mov    dx,offset msgbadpare    ; say using even parity
  1449.     jmp    short parchk6
  1450. parchk4:cmp    dh,4            ; got four odd parity chars?
  1451.     jne    parchk5            ; ne = no
  1452.     mov    badpflag,parodd+80h    ; say odd parity and flagging bit
  1453.     mov    dx,offset msgbadparo    ; say using odd parity
  1454.     jmp    short parchk6
  1455. parchk5:mov    badpflag,parmrk+80h    ; say mark parity and flagging bit
  1456.     mov    dx,offset msgbadparm    ; say using mark parity
  1457. parchk6:call    ermsg1
  1458.     call    captdol            ; write in log file too
  1459. parchk7:pop    dx
  1460.     pop    cx
  1461.     pop    bx
  1462.     pop    ax
  1463.     ret
  1464. parchk    endp
  1465.  
  1466. ; General packet buffer structure manipulation routines. The packet buffers
  1467. ; consist of a arrays of words, bufuse and buflist, an array of pktinfo
  1468. ; structure packet descriptors, and a subdivided main buffer named "bufbuf".
  1469. ; Each pktinfo member describes a packet by holding the address (offset within
  1470. ; segment data) of the data field of a packet (datadr), the length of that
  1471. ; field in bytes (datsize), the number of bytes currently occupying that field
  1472. ; (datlen), the packet sequence number, an ack-done flag byte, and the number
  1473. ; of retries of the packet.
  1474. ; The data field is a portion of main buffer "bufbuf" with space for an extra
  1475. ; null terminator byte required by the packet routines rpack and spack. It
  1476. ; is sectioned into trans.windo buffers by procedure makebuf.
  1477. ; Bufuse is an array holding an in-use flag for each pktinfo member; 0 means
  1478. ; the member is free, otherwise a caller has allocated the member via getbuf.
  1479. ; Buflist holds the address (offset in segment data) of each pktinfo member,
  1480. ; for rapid list searching.
  1481. ;
  1482. ; Packet structures are constructed and initialized by procedure makebuf.
  1483. ; Other procedures below access the members in various ways. Details of
  1484. ; buffer construction should remain local to these routines.
  1485. ; Generally, SI is used to point to a pktinfo member and AL holds a packet
  1486. ; sequence number (0 - 63 binary). BX and CX are used for some status reports.
  1487. ;
  1488. ;  bufuse    buflist            pktlist (group of pktinfo members)
  1489. ;  -------    -------        -------------------------------------------
  1490. ; 0 for unused              | datadr,datlen,datsize,seqnum,ackdone,numtry |
  1491. ;            pointers to ->+ datadr,datlen,datsize,seqnum,ackdone,numtry |
  1492. ; 1 for used              | datadr,datlen,datsize,seqnum,ackdone,numtry |
  1493. ;                        etc
  1494. ;
  1495. ; Construct new buffers, cleared, by subdividing main buffer "bufbuf"
  1496. ; according to the number of windows (variable trans.windo). Makes these
  1497. ; buffers available to getbuf and other manipulation routines. All regs
  1498. ; are preserved.
  1499. makebuf    proc    far
  1500.     push    ax
  1501.     push    bx
  1502.     push    cx
  1503.     push    dx
  1504.     push    si
  1505.     mov    ax,maxpack        ; size of main packet buffer (bufbuf)
  1506.     mov    cl,trans.windo        ; number of window slots
  1507.     xor    ch,ch
  1508.     cmp    cx,1            ; 0 or 1 window slots = initial slot
  1509.     jae    makebu1            ; a = more than one, compute
  1510.     inc    cx
  1511.     jmp    short makebu2        ; save a division by one
  1512. makebu1:xor    dx,dx
  1513.     div    cx            ; size of windowed buffer to ax
  1514. makebu2:mov    dx,ax            ; keep buffer size in dx
  1515.     mov    bufnum,cx        ; number of buffers
  1516.     mov    ax,offset bufbuf    ; where buffers start
  1517.     mov    si,offset pktlist    ; where pktinfo group starts
  1518.     xor    bx,bx            ; index (words)
  1519. makebu3:mov    bufuse[bx],0        ; say buffer slot is not used yet
  1520.     mov    buflist[bx],si        ; pointer to pktinfo member
  1521.     mov    [si].datadr,ax        ; address of data field
  1522.     mov    [si].datsize,dx        ; data buffer size
  1523.     mov    [si].numtry,0        ; clear number tries for this buffer
  1524.     mov    [si].ackdone,0        ; not acked yet
  1525.     mov    [si].seqnum,0        ; a dummy sequence number
  1526.     add    si,size pktinfo        ; next pktinfo member
  1527.     add    ax,dx            ; pointer to next buffer
  1528.     inc    ax            ; leave space for null pointer
  1529.     add    bx,2            ; next buflist slot
  1530.     loop    makebu3            ; make another structure member
  1531.     mov    windused,0        ; no slots used yet
  1532.     pop    si
  1533.     pop    dx
  1534.     pop    cx
  1535.     pop    bx
  1536.     pop    ax
  1537.     ret
  1538. makebuf    endp
  1539.  
  1540. ; Allocate a buffer. Return carry clear and SI pointing at fresh pktinfo
  1541. ; structure, or if failure return carry set and all regs preserved.
  1542. getbuf    proc    far
  1543.     push    ax
  1544.     push    cx
  1545.     push    si
  1546.     xor    si,si            ; index
  1547.     mov    cx,bufnum        ; number of buffers
  1548.     jcxz    getbuf2            ; 0 means none, error
  1549. getbuf1:cmp    bufuse[si],0        ; is this slot in use?
  1550.     je    getbuf3            ; e = no, grab it
  1551.     add    si,2            ; try next slot
  1552.     loop    getbuf1            ; fall through on no free buffers
  1553. getbuf2:pop    si            ; get here if all are in use
  1554.     pop    cx
  1555.     pop    ax
  1556.     stc                ; return failure, si preserved
  1557.     ret
  1558.  
  1559. getbuf3:mov    bufuse[si],1        ; mark buffer as being in use
  1560.     inc    windused        ; one more slot in use
  1561.     mov    si,buflist[si]        ; address of pktinfo member
  1562.     mov    al,pktnum        ; next sequence number to be used
  1563.     mov    [si].seqnum,al        ; use it as sequence number
  1564.     mov    [si].datlen,0        ; no data in packet
  1565.     mov    [si].numtry,0        ; clear number tries for this buffer
  1566.     mov    [si].ackdone,0        ; not acked yet
  1567.     pop    cx            ; discard originally saved si
  1568.     pop    cx
  1569.     pop    ax
  1570.     clc                ; return success, buffer ptr in si
  1571.     ret
  1572. getbuf    endp
  1573.  
  1574. ; Release all buffers (just marks them as free).
  1575.  
  1576. bufclr    proc    far
  1577.     push    ax
  1578.     push    cx
  1579.     push    di
  1580.     push    es
  1581.     push    ds
  1582.     pop    es
  1583.     mov    cx,maxwind        ; max number of buffers
  1584.     xor    ax,ax
  1585.     mov    di,offset bufuse    ; buffer in-use list
  1586.     cld
  1587.     rep    stosw            ; store zeros to clear the buffers
  1588.     mov    windused,0        ; number now used (none)
  1589.     pop    es
  1590.     pop    di
  1591.     pop    cx
  1592.     pop    ax
  1593.     ret
  1594. bufclr    endp
  1595.  
  1596. ; Release buffer whose pktinfo pointer is in SI.
  1597. ; Return carry clear if success, or carry set if failure.
  1598. bufrel    proc    far
  1599.     push    bx
  1600.     push    cx
  1601.     mov    cx,bufnum        ; number of buffers
  1602.     xor    bx,bx
  1603. bufrel1:cmp    buflist[bx],si        ; compare addresses, match?
  1604.     je    bufrel2            ; e = yes, found it
  1605.     add    bx,2
  1606.     loop    bufrel1
  1607.     pop    cx
  1608.     pop    bx
  1609.     stc                ; no such buffer
  1610.     ret
  1611. bufrel2:mov    bufuse[bx],0        ; say buffer is no longer in use
  1612.     dec    windused        ; one less used buffer
  1613.     pop    cx
  1614.     pop    bx
  1615.     clc
  1616.     ret
  1617. bufrel    endp
  1618.  
  1619. ; Returns in BX the "packet pointer" for the buffer with the same seqnum as
  1620. ; provided in AL. Returns carry set if no match found. Modifies BX.
  1621. pakptr    proc    far
  1622.     push    cx
  1623.     push    di
  1624.     mov    cx,bufnum        ; number of buffers
  1625.     xor    di,di            ; buffer index for tests
  1626. pakptr1:cmp    bufuse[di],0        ; is buffer vacant?
  1627.     je    pakptr2            ; e = yes, ignore
  1628.     mov    bx,buflist[di]        ; bx = address of pktinfo member
  1629.     cmp    al,[bx].seqnum        ; is this the desired sequence number?
  1630.     je    pakptr3            ; e = yes
  1631. pakptr2:add    di,2            ; next buffer index
  1632.     loop    pakptr1            ; do next test
  1633.     xor    bx,bx            ; say no pointer
  1634.     stc                ; set carry for failure
  1635.     pop    di
  1636.     pop    cx
  1637.     ret
  1638. pakptr3:clc                ; success, BX has buffer pointer
  1639.     pop    di
  1640.     pop    cx
  1641.     ret
  1642. pakptr    endp
  1643.  
  1644. ; Returns in AH count of packets with a given sequence number supplied in AL
  1645. ; and returns in BX the packet pointer of the last matching entry.
  1646. ; Used to detect duplicated packets.
  1647. pakdup    proc    far
  1648.     push    cx
  1649.     push    dx
  1650.     push    di
  1651.     mov    cx,bufnum        ; number of buffers
  1652.     xor    di,di            ; buffer index for tests
  1653.     xor    ah,ah            ; number of pkts with seqnum in al
  1654.     mov    dx,-1            ; a bad pointer
  1655. pakdup1:cmp    bufuse[di],0        ; is buffer vacant?
  1656.     je    pakdup2            ; e = yes, ignore
  1657.     mov    bx,buflist[di]        ; bx = address of pktinfo member
  1658.     cmp    al,[bx].seqnum        ; is this the desired sequence number?
  1659.     jne    pakdup2            ; ne = no
  1660.     mov    dx,bx            ; yes, remember last pointer
  1661.     inc    ah            ; count a found packet
  1662. pakdup2:add    di,2            ; next buffer index
  1663.     loop    pakdup1            ; do next test
  1664.     mov    bx,dx            ; return last matching member's ptr
  1665.     pop    di
  1666.     pop    dx
  1667.     pop    cx
  1668.     or    ah,ah            ; any found?
  1669.     jz    pakdup3            ; z = no
  1670.     clc                ; return success
  1671.     ret
  1672. pakdup3:stc                ; return failure
  1673.     ret
  1674. pakdup    endp
  1675.     
  1676. ; Find sequence number of first free window slot and return it in AL,
  1677. ; Return carry set and al = windlow if window is full (no free slots).
  1678. firstfree proc    far
  1679.     mov    al,windlow        ; start looking at windlow
  1680.     mov    ah,al
  1681.     add    ah,trans.windo
  1682.     and    ah,3fh            ; ah = 1+top window seq number, mod 64
  1683. firstf1:push    bx
  1684.     call    pakptr            ; buffer in use for seqnum in AL?
  1685.     pop    bx
  1686.     jc    firstf2            ; c = no, seq number in not in use
  1687.     inc    al            ; next sequence number
  1688.     and    al,3fh            ; modulo 64
  1689.     cmp    al,ah            ; done all yet?
  1690.     jne    firstf1            ; ne = no, do more
  1691.     mov    al,windlow        ; a safety measure
  1692.     stc                ; carry set to say no free slots
  1693.     ret
  1694. firstf2:clc                ; success, al has first free seqnum
  1695.     ret
  1696. firstfree endp
  1697.  
  1698. ; Check sequence number for lying in the current or previous window or
  1699. ; outside either window.
  1700. ; Enter with sequence number of received packet in [si].seqnum.
  1701. ; Returns:
  1702. ;    carry clear and cx =  0 if [si].seqnum is within the current window,
  1703. ;    carry set   and cx = -1 if [si].seqnum is inside previous window,
  1704. ;    carry set   and cx = +1 if [si].seqnum is outside any window.
  1705. chkwind    proc    far
  1706.     mov    ch,[si].seqnum        ; current packet sequence number
  1707.     mov    cl,trans.windo        ; number of window slots
  1708.     sub    ch,windlow        ; ch = distance from windlow
  1709.     jc    chkwin1            ; c = negative result
  1710.     cmp    ch,cl            ; span greater than # window slots?
  1711.     jb    chkwinz            ; b = no, in current window
  1712.     sub    ch,64            ; distance measured the other way
  1713.     neg    ch
  1714.     cmp    ch,cl            ; more than window size?
  1715.     ja    chkwinp            ; a = yes, outside any window
  1716.     jmp    short chkwinm        ; else in previous window
  1717.  
  1718.                     ; sequence number less than windlow
  1719. chkwin1:neg    ch            ; distance, positive, cl >= ch
  1720.     cmp    ch,cl            ; more than window size?
  1721.     ja    chkwin2            ; a = yes, maybe this window
  1722.     jmp    short chkwinm        ; no, in previous window
  1723.  
  1724. chkwin2:sub    ch,64            ; distance measured the other way
  1725.     neg    ch
  1726.     cmp    ch,cl            ; greater than window size?
  1727.     jb    chkwinz            ; b = no, in current window
  1728.                     ; else outside any window
  1729.  
  1730. chkwinp:mov    cx,1            ; outside any window
  1731.     stc                ; carry set for outside current window
  1732.     ret
  1733. chkwinz:xor    cx,cx            ; inside current window
  1734.     clc                ; carry clear, inside current window
  1735.     ret
  1736. chkwinm:mov    cx,-1            ; in previous window
  1737.     stc                ; carry set for outside current window
  1738.     ret
  1739. chkwind    endp
  1740.  
  1741. code1    ends
  1742.     end
  1743.