home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSSCOM.ASM < prev    next >
Assembly Source File  |  1993-05-14  |  59KB  |  1,706 lines

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