home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
msvp98b1.lzh
/
MSNTNI.ORG
< prev
next >
Wrap
Text File
|
1993-05-14
|
19KB
|
721 lines
NAME MSNTNI
; File MSNTNI.ASM
; Telnet interface to MS-DOS Kermit
;
; Copyright (C) 1985, 1992, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or institution
; to use this software as long as it is not sold for profit. This copyright
; notice must be retained. This software may not be included in commercial
; products without written permission of Columbia University.
;
; Written by Joe R. Doupnik, Utah State University,
; jrd@cc.usu.edu, jrd@usu.Bitnet.
;
; Edit history
; 6 Sept 1991 version 3.11
; Last edit 28 Jan 1992
include mssdef.h
getintv equ 35h ; DOS get interrupt vector to es:bx
bapicon equ 0a0h ; 3Com BAPI, connect to port
bapidisc equ 0a1h ; 3Com BAPI, disconnect
bapiwrit equ 0a4h ; 3Com BAPI, write block
bapiread equ 0a5h ; 3Com BAPI, read block
bapibrk equ 0a6h ; 3Com BAPI, send short break
bapistat equ 0a7h ; 3Com BAPI, read status (# chars to be read)
bapihere equ 0afh ; 3Com BAPI, presence check
bapieecm equ 0b0h ; 3Com BAPI, enable/disable ECM char
bapiecm equ 0b1h ; 3Com BAPI, trap Enter Command Mode char
data segment public 'kdata'
extrn tcptos:word ; top of stack for TCP code
extrn flags:byte, yflags:byte, portval:word, ttyact:byte
extrn ftogmod:dword, crt_lins:byte, crt_cols:byte
data ends
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
_DATA SEGMENT
public _kmyip, _knetmask, _kdomain, _kgateway, _kns1, _kns2, _khost
public _kbcast, _bapibuf, _bapireq, _bapiret, _msgcnt, _msgbuf
public _display_mode, _kport, _kpdint, _kserver, _kdebug, _kterm
public _ktttype, _kterm_lines, _kterm_cols
extrn _my_ip_addr:dword, _sin_mask:dword
db 'DUMMY',0 ; null pointer guard
_kmyip db 33 dup (0) ; our IP number
_knetmask db 33 dup (0) ; our netmask
_kdomain db 33 dup (0) ; our domain
_kgateway db 33 dup (0) ; our gateway
_kns1 db 33 dup (0) ; our nameserver #1
_kns2 db 33 dup (0) ; our nameserver #2
_khost db 61 dup (0) ; remote host name/IP #
_kbcast db 33 dup (0) ; broadcast IP
_ktttype db 33 dup (0) ; terminal-type override string
_kserver dw 0 ; non-zero for Kermit server
_kport dw 23 ; TCP port (Telnet = 23)
_kpdint dw 0 ; Packet Driver Int, 0 = search
_kdebug dw 0 ; if SET DEBUG ON is effective
_kterm dw 0 ; terminal type index, see mssdef.h
_kterm_lines db 0 ; terminal screen height (24)
_kterm_cols db 0 ; terminal screen width (80)
oldint8 dd 0 ; original Int 8 owner
tcpstack dd 0 ; TCP code stack
stack8 dd 0 ; stack at Int 8 invokation
kstack dw 0 ; Kermit mainline stack pointer
tempax dw 0 ; a temp
tcpflag db 0 ; who is running TCP code: 1=Kermit, 2=Int 8
tcpdata dw 0 ; Kermit offset of "tcpdata" block
int8cnt db 0 ; Int 8 times called counter
_display_mode db 0 ; msg, none if == 0
opcode db 0 ; BAPI op code
userbuf dd 0 ; BAPI user's comms buffer address
_bapireq dw 0 ; BAPI count of chars requested
_bapiret dw 0 ; BAPI count of chars processed
buflen equ 512
_bapibuf db buflen dup (0) ; BAPI buffer in TCP address space
_msgcnt dw 0 ; count of bytes in msg buffer
_msgbuf db 256 dup (0) ; interrupt level msg buffer
_DATA ENDS
_TEXT segment
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
extrn _serial_handler:near, _main:near, _exit:near
extrn _pkt_release:near, _tcp_tick:near, _bcopy:near, _itoa:near
extrn _strlen:near, _strcpy:near
public _enable
enable proc near
_enable equ this byte
sti
ret
enable endp
public _disable
disable proc near
_disable equ this byte
cli
ret
disable endp
; Hook Interrupts 8h. Return AX = 1 if successful else 0.
public _hookvect
hookvect proc near
_hookvect equ this byte
push bp
mov bp,sp
mov ax,bp
add ax,2+2 ; C sp just before this call
mov word ptr tcpstack,ax ; save as main prog stack level
push es
mov ah,getintv ; get interrupt vector
mov al,8 ; vector number
int dos
mov ax,es
mov cx,cs
cmp ax,cx ; points to us now?
je hook2 ; e = yes, do not touch
mov word ptr DGROUP:oldint8+2,ax ; save segment
mov word ptr DGROUP:oldint8,bx ; save offset
mov dx,offset ourtimer ; new handler
push ds
mov ax,cs ; segment
mov ds,ax
mov al,8 ; for Int 8
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
hook2: mov tcpflag,1 ; say Kermit but not Int 8 is running TCP
mov ax,1 ; return 1 for success
pop es
pop bp
ret
hook3: call unhookvect ; put any back
xor ax,ax ; return 0 for failure
pop es
pop bp
ret
hookvect endp
public _unhookvect
unhookvect proc near
_unhookvect equ this byte
push bp
mov bp,sp
push es
push bx
push cx
clc
mov tempax,0 ; assume failure status
mov ah,getintv ; get interrupt vector
clc
mov al,8 ; vector number
int dos
jc unhook2 ; c = failed
mov ax,es ; es:bx is current owner, us?
mov cx,cs
cmp ax,cx ; seg should be right here
jne unhook2 ; ne = is not
cmp bx,offset ourtimer ; should be the same too
jne unhook2 ; ne = is not, let them have the int
mov ax,word ptr DGROUP:oldint8+2 ; segment
mov dx,word ptr DGROUP:oldint8 ; offset
mov cx,dx
or cx,ax ; was it used by us?
jz unhook2 ; z = no, leave alone
push ds
mov ds,ax
mov al,8 ; for Int 8
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
and tcpflag,not 2 ; Int 8 no longer touches TCP
mov word ptr DGROUP:oldint8,0
mov word ptr DGROUP:oldint8+2,0
mov tempax,1 ; success status
jmp short unhook3
unhook2:mov tempax,0 ; failure
unhook3:mov ax,tempax ; return status (1=success, 0=fail)
pop cx
pop bx
pop es
pop bp
ret
unhookvect endp
; Int 8 routine to call the TCP code if Kermit main body does not.
ourtimer proc near
push ds
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pushf ; simulate interrupt invokation
call dword ptr DGROUP:oldint8 ; call previous owner of Int 8
mov ax,DGROUP ; set addressibility to our dgroup
mov ds,ax
test tcpflag,1+2 ; is TCP code running now?
jnz ourtim2 ; nz = yes, so we don't run now
mov al,int8cnt ; get our times-called counter
inc al ; up once again
and al,7 ; keep 3 bits, about .5 sec @18.2tic/s
mov int8cnt,al ; store
or al,al ; is it zero?
jnz ourtim2 ; nz = no, go away for awhile
or tcpflag,2 ; say we are running the TCP code
push bp
push bx
push cx
push dx
push si
push di
push es
cli
mov ax,ss
mov word ptr stack8+2,ax ; save current stack
mov word ptr stack8,sp
mov ax,word ptr tcpstack+2 ; get TCP stack seg
mov ss,ax ; set to TCP stack
mov sp,word ptr tcpstack
sti ; restart interrupts
xor ax,ax ; socket pointer, null
push ax ; set call frame for tcp_tick(NULL)
call _tcp_tick ; process some incoming packets
pop ax ; clean call frame
mov ax,word ptr stack8+2 ; get original stack seg
cli
mov ss,ax
mov sp,word ptr stack8
sti
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop bp
and tcpflag,not 2 ; finished our running of TCP code
ourtim2:pop ax
pop ds
iret
ourtimer endp
; This routine is invoked from outside by a Far call. Enter with the caller's
; registers but our CS. Switch stacks and data segments.
; This version supports 3Com BAPI calls and does the near/far stuff via
; a local buffer.
public ktcpcom
ktcpcom proc FAR ; i/o service routine
assume ds:DGROUP
push ds
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pop ax
test tcpflag,2 ; is Int 8 running TCP?
jz ourser8 ; z = no, should never be yes, but...
mov ah,1 ; say no char written
xor cx,cx ; chars written
pop ds
ret
ourser8:or tcpflag,1 ; say we are running TCP
push es ; save regs on the user's stack
push di
push si
push dx
push bx
push bp
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pop ax
mov kstack,sp ; remember caller's stack now
mov sp,word ptr tcpstack ; move to our TCP stack
mov word ptr userbuf,bx ; remember caller's es:bx
mov word ptr userbuf+2,es
mov _bapireq,cx ; requested char count to TCP code
mov _bapiret,0 ; init returned CX char count
mov opcode,ah ; remember operation for return proc
cmp ah,bapihere ; presence check?
jne ourser6 ; ne = no
mov ax,0af01h ; return this value
jmp ourser4 ; done
ourser6:
cmp ah,bapiwrit ; BAPI write?
jne ourser2 ; ne = no
push ax
push cx
push es
push ds
mov di,offset DGROUP:_bapibuf ; where it goes
mov si,bx ; es:bx, whence it comes
mov bx,es
mov ax,ds
mov es,ax
mov ds,bx
cld
cmp cx,buflen ; largest block i/o we allow here
jbe ourser1 ; be = ok
mov cx,buflen ; truncate the request
ourser1:shr cx,1
jnc ourser1a
movsb
ourser1a:rep movsw ; copy their buffer to ours
pop ds
pop es
pop cx
pop ax
ourser2:cmp ah,bapiread ; read?
jne ourser3 ; ne = no
cmp _msgcnt,0 ; any outstanding msgs from TCP?
je ourser3 ; e = no msgs
call oursmsg ; send back the msgs instead
jmp short ourser4 ; ax has status of ok
ourser3:sti ; let other ints happen
mov bx,dgroup ; set up es to dgroup too
mov es,bx ; bx is not needed at this time
xchg ah,al ; put function code in al
xor ah,ah
push ax ; setup call frame
call _serial_handler ; a near call, _serial_handler(ax)
cli ; reg ax has return status
add sp,2 ; clean stack
mov cx,dgroup ; safety check, not really needed
mov ds,cx
mov cx,_bapiret ; count of chars returned
cmp opcode,bapiread ; BAPI read?
jne ourser4 ; ne = no
jcxz ourser4 ; z = nothing to copy
push ax
push cx
mov si,offset DGROUP:_bapibuf ; whence it comes
mov di,word ptr userbuf ; where it goes
mov ax,word ptr userbuf+2 ; segment
mov es,ax
cld
shr cx,1
jnc ourser3a
movsb
ourser3a:rep movsw ; copy our buffer to theirs
pop cx ; return count in cx
pop ax ; return result code in ah, cnt in cx
ourser4:clc ; assume success
xchg ah,al ; put return status in ah
xor al,al
cmp ah,3 ; serious error status?
jb ourserx ; b = no, zero is success
stc ; set carry too
ourserx:mov sp,kstack ; move to caller's stack
and tcpflag,not 1 ; say we are not running TCP
pop bp
pop bx
pop dx
pop si
pop di
pop es
pop ds
ret ; AX and CX are changed as returns
ktcpcom endp
; Copy contents of msgbuf (local Telnet msg collector buffer) to main body.
oursmsg proc near
mov cx,_msgcnt
jcxz ourser3 ; z = no msgs
cmp cx,_bapireq ; longer than request?
jbe oursmsg1 ; be = no
mov cx,_bapireq ; do this much now
oursmsg1:push cx
mov si,offset DGROUP:_msgbuf ; whence it comes
mov di,word ptr userbuf ; where it goes
mov ax,word ptr userbuf+2 ; segment
mov es,ax
cld
rep movsb ; copy our buffer to theirs
pop cx ; return count in cx
mov _bapiret,cx ; return count to user
sub _msgcnt,cx ; deduct chars relayed
cmp _msgcnt,0 ; examine remainder
je oursmsg3 ; e = none
mov ax,_msgcnt ; count
push ax
mov ax,offset DGROUP:_msgbuf
push ax ; destination
add ax,_msgcnt ; source
push ax
call _bcopy ; copy to beginning of buffer
add sp,6 ; clean stack
oursmsg3:mov ax,0 ; return status of success
ret
oursmsg endp
; tcpaddress db 'unknown',(32-($-tcpaddress)) dup (0),0
; tcpsubnet db '255.255.255.0',(32-($-tcpsubnet)) dup (0),0
; tcpdomain db 'unknown',(32-($-tcpdomain)) dup (0),0
; tcpgateway db 'unknown',(32-($-tcpgateway)) dup (0),0
; tcpprimens db 'unknown',(32-($-tcpprimens)) dup (0),0
; tcpsecondns db 'unknown',(32-($-tcpsecondns)) dup (0),0
; tcphost db (60 -($-tcphost)) dup (0),0
; tcpbcast db '255.255.255.255',(32-($-tcpbcast)) dup (0),0
; tcpport dw 23
; tcppdint dw 60h
;
; tcpdata dw offset tcpaddress ; externally visible far pointers
; dw offset tcpsubnet
; dw offset tcpdomain
; dw offset tcpgateway
; dw offset tcpprimens
; dw offset tcpsecondns
; dw offset tcphost
; dw offset tcpbcast
; dw offset tcpport
; dw offset tcppdint
; dw offset tcpttbuf
public ktcpstart
ktcpstart proc far
ASSUME DS:DATA, ES:DGROUP
push es ; save regs on main Kermit stack
push ds
push di
push si
push dx
push cx
push bx
push bp
mov ax,DGROUP
mov es,ax ; destination is the TCP module
cld
mov tcpdata,bx ; store offset of Kermit data block
mov si,[bx] ; get offset of our IP address
mov di,offset DGROUP:_kmyip ; our storage slot
mov cx,16 ; max bytes
start5: lodsb
stosb
or al,al
loopne start5 ; copy IP address string, asciiz
xor al,al ; extra terminator
stosb
mov si,[bx+2] ; get offset in Kermit
mov di,offset DGROUP:_knetmask
mov cx,16
start6: lodsb
stosb
or al,al
loopne start6
xor al,al
stosb
mov si,[bx+4] ; get offset in Kermit
mov di,offset DGROUP:_kdomain
mov cx,32
start7: lodsb
stosb
or al,al
loopne start7
xor al,al
stosb
mov si,[bx+6] ; get offset in Kermit
mov di,offset DGROUP:_kgateway
mov cx,32
start8: lodsb
stosb
or al,al
loopne start8
xor al,al
stosb
mov si,[bx+8] ; get offset in Kermit
mov di,offset DGROUP:_kns1
mov cx,32
start9: lodsb
stosb
or al,al
loopne start9
xor al,al
stosb
mov si,[bx+10] ; get offset in Kermit
mov di,offset DGROUP:_kns2
mov cx,32
start10:lodsb
stosb
or al,al
loopne start10
xor al,al
stosb
mov si,[bx+12] ; get offset in Kermit
mov di,offset DGROUP:_khost
mov cx,60
start11:lodsb
stosb
or al,al
loopne start11
xor al,al
stosb
mov si,[bx+14] ; broadcast address
mov di,offset DGROUP:_kbcast
mov cx,32
start12:lodsb
stosb
or al,al
loopne start12
xor al,al
stosb
mov si,[bx+16] ; TCP port
mov ax,[si]
mov es:_kport,ax
mov si,[bx+18] ; Packet Driver Interrupt
mov ax,[si]
mov es:_kpdint,ax ; 0 means scan
mov si,[bx+20] ; offset of term-type string
mov di,offset DGROUP:_ktttype ; local storage of the string
mov cx,32
start13:lodsb
stosb
or al,al
loopne start13
xor al,al
stosb
mov es:_display_mode,0 ; presume quiet screen
test flags.remflg,dquiet ; quiet display mode?
jnz start14 ; nz = yes. Don't write to screen
inc es:_display_mode ; say can write to screen
start14:mov es:_kserver,0 ; assume not a server
test flags.remflg,dserver ; Server mode?
jz start15 ; z = no
mov es:_kserver,1 ; say being a server (do Listen)
start15:mov es:_kdebug,0 ; assume no debug mode
test flags.debug,0ffh ; debugging active?
jz start16 ; z = no
inc es:_kdebug ; turn on debugging here
start16:mov ax,flags.vtflg ; get terminal type index
mov es:_kterm,ax
mov al,crt_lins ; get display height
mov es:_kterm_lines,al
mov al,crt_cols ; get display width
mov es:_kterm_cols,al
start20:mov bx,tcptos ; top of stack for tcp code
assume ds:DGROUP, ES:NOTHING
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
mov es,ax
mov word ptr tcpstack+2,ax ; set TCP stack seg
mov word ptr kstack,sp ; store Kermit's stack ptr
mov sp,bx ; new TCP stack pointer, DGROUP based
mov bp,sp ; preset this as insurance
or tcpflag,1 ; say this is running TCP code
call _main ; call the C code
and tcpflag,not 1 ; finished running tcp code
mov sp,word ptr kstack ; restore for Kermit's main stack
mov bx,data ; main Kermit data segment
mov es,bx
mov bx,tcpdata ; pointer to storage word
mov cx,_kpdint ; report back Packet Driver Int
mov bx,es:[bx+18] ; get address of storage slot
mov es:[bx],cx ; store value in main data seg
pop bp ; restore regs, Kermit's main stack
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
ret ; return to caller
ktcpstart endp
public ktcpstop
ktcpstop proc far
assume ds:dgroup, es:nothing
push es ; save regs on the user's stack
push ds
push di
push si
push dx
push cx
push bx
push bp
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
mov kstack,sp ; remember Kermit's main sp
or tcpflag,1 ; say we are running TCP code
mov ax,word ptr tcpstack ; set sp to TCP sp
mov sp,ax
mov bp,sp ; preset this as insurance
push ds
pop es
xor ax,ax
push ax ; exit(0) setup
call _exit
add sp,2 ; returns status in AX
mov tempax,ax
mov ax,word ptr tcpstack ; set sp to TCP sp again
mov sp,ax
mov bp,sp ; preset this as insurance
call _pkt_release ; do this as insurance
mov ax,tempax ; regain status
push ax
call unhookvect ; ditto
pop ax
mov tcpflag,0 ; no one is running the TCP code
mov sp,kstack
pop bp ; restore regs, Kermit's main stack
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
ret ; return to caller
ktcpstop endp
public _readback
_readback proc near
assume ds:dgroup, es:dgroup
push bp
mov bp,sp
push si
push di
push es
mov ax,data
mov es,ax
mov si,offset dgroup:_kmyip
push si
push si
call _strlen ; get length of string
add sp,2
pop si
mov di,tcpdata ; copy to Kermit main body
mov di,es:[di] ; offset of the string
mov cx,ax
cld
rep movsb
xor al,al
stosb ; terminator
mov si,offset dgroup:_knetmask
mov di,tcpdata
mov di,es:[di+2]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kgateway
mov di,tcpdata
mov di,es:[di+6]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kns1
mov di,tcpdata
mov di,es:[di+8]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kns2
mov di,tcpdata
mov di,es:[di+10]
mov cx,17
rep movsb
stosb ; terminator
pop es
pop si
pop di
pop bp
ret
_readback endp
; Track Telnet echo variable (0 do not do local echo) into terminal emulator
; and Kermit main body. Call this each time Telnet options change echo.
public _kecho
_kecho proc near
assume ds:data, es:dgroup
push bp
mov bp,sp
push ds
push es
push si
push ax
mov ax,data ; Kermit main data segment
mov ds,ax
mov ax,dgroup
mov es,ax
mov ax,[bp+4+0] ; get Telnet _echo variable
and yflags,not lclecho ; assume no local echo in emulator
or al,al ; Telnet local echo is off?
jz kecho1 ; z = yes
mov al,lclecho ; lclecho flag for emulator
kecho1: or yflags,al ; set terminal emulator
mov si,portval
mov [si].ecoflg,al ; set mainline SET echo flag
cmp ttyact,0 ; acting as a Terminal?
je kecho2 ; e = no
call dword ptr ftogmod ; toggle mode line
call dword ptr ftogmod ; and again
kecho2: pop ax
pop si
pop es
pop ds
pop bp
ret
_kecho endp
_TEXT ends
end