NAME msntni ; File MSNTNI.ASM ; Telnet interface to MS-DOS Kermit ; ; Copyright (C) 1982, 1997, Trustees of Columbia University in the ; City of New York. The MS-DOS Kermit software may not be, in whole ; or in part, licensed or sold for profit as a software product itself, ; nor may it be included in or distributed with commercial products ; or otherwise distributed by commercial concerns to their clients ; or customers without written permission of the Office of Kermit ; Development and Distribution, Columbia University. This copyright ; notice must not be removed, altered, or obscured. ; ; Written by Joe R. Doupnik, Utah State University, ; jrd@cc.usu.edu, jrd@usu.Bitnet. ; ; Edit history ; 12 Jan 1995 version 3.14 ; Last edit ; 12 Jan 1995 ; ; Some rules of the road. ; Starting a session: call ktpcopen. This will ensure the interrupts are ; hooked and will start a new session. Ktcpopen will return the ident of ; the new session, or -1 upon failure. ; Stopping a session: this must be done from outside Telnet. Call ktcpclose ; with a particular session ident (0.. MAXSESSIONS-1) to close that session ; or call it with an ident of -1 to close all and shutdown TCP. Ktcpclose ; will return with the ident of the next (cyclic) active session, or -1 if ; none remain active. Register AX holds incoming indent, outgoing status. ; When TCP/IP shuts down it releases all interrupts and disengages from the ; Packet Driver. This will occur upon closing the last active connection. ; ; Swapping active sessions: call ktcpswap with a new session ident to change ; to that new one. This will return with the new ident if successful, or -1. ; We have to guess session idents so an outside manager can pick and choose. ; Use ktcpswap to resume a session because ktcpstart always tries to start a ; new one. include mssdef.h 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 crt_lins:byte, crt_cols:byte extrn tcp_status:word extrn tcpaddress:byte, tcpsubnet:byte, tcpdomain:byte extrn tcpgateway:byte, tcpprimens:byte, tcpsecondns:byte extrn tcphost:byte, tcpbcast:byte, tcpbtpserver:byte extrn tcpport:word, tcppdint:word, tcpttbuf:byte, tcpnewline:byte extrn tcpdebug:byte, tcpmode:byte, tcpmss:word, tcpbtpkind:byte extrn tloghnd:word, tcp_rto:word ifndef no_terminal extrn ftogmod:dword endif ; no_terminal 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, _bapiadr, _bapireq, _bapiret public _display_mode, _kport, _kpdint, _kserver, _kdebug, _kterm public _ktttype, _kterm_lines, _kterm_cols, _kbtpserver, _tcp_status public _tcpflag, _ktnmode, _ktcpmss, int8cnt extrn _msgcnt:word, _msgbuf:byte, _echo:byte, _bootmethod:byte db 10 dup (0) ; guard db 'DUMMY',0 ; null pointer guard _kmyip db 17 dup (0) ; our IP number _knetmask db 17 dup (0) ; our netmask _kdomain db 33 dup (0) ; our domain _kgateway db 33 dup (0) ; our gateway _kns1 db 17 dup (0) ; our nameserver #1 _kns2 db 17 dup (0) ; our nameserver #2 _khost db 61 dup (0) ; remote host name/IP # _kbcast db 17 dup (0) ; broadcast IP _ktttype db 33 dup (0) ; terminal-type override string _kbtpserver db 17 dup (0) ; Bootp server which responded _kserver dw 0 ; non-zero for Kermit server _kport dw 23 ; TCP port (Telnet = 23) _kpdint dw 0 ; Packet Driver Int, 0 = search _kdebug db 0 ; if SET DEBUG ON is effective _ktnmode db 0 ; Telnet mode (0=NVT-ASCII,1=BINARY) _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) _ktcpmss dw 0 ; MSS override 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 int8cnt db 0 ; Int 8 times called counter hooked db 0 ; Int 8 hooked status (0 = unhooked) _display_mode db 0 ; msg, none if == 0 _bapireq dw 0 ; BAPI count of chars requested _bapiret dw 0 ; BAPI count of chars processed _bapiadr dd 0 _tcp_status dw 0 ; tcp/ip status from msntnd.c _DATA ENDS _TEXT segment ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, es:nothing extrn _serial_handler:near, _tnmain:near, _tnexit:near extrn _pkt_release:near, _tcp_tick:near extrn _strlen:near, _strcpy:near, _session_close:near extrn _session_change:near public cpatch cpatch equ this byte db (100-($-cpatch)) dup (0) ; _TEXT segment patch buffer 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 Interrupt 8h. Return AX = 1 if successful else 0. ; For use only by Telnet code as an internal procedure. public _hookvect hookvect proc near _hookvect equ this byte cmp hooked,0 ; hooked already? je hook0 ; e = no mov ax,1 ; say success ret hook0: push bp mov bp,sp mov ax,bp add ax,2+2 ; C sp just before this call cmp word ptr tcpstack+2,0 ; have setup stack? jne hook1 ; ne = yes mov word ptr tcpstack,ax ; save as main prog stack level hook1: 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,setintv ; set interrupt address from ds:dx int dos pop ds mov hooked,1 ; say have hooked vector 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 ; For use only by Telnet code as an internal procedure. public _unhookvect unhookvect proc near _unhookvect equ this byte cmp hooked,0 ; hooked the vector? jne unhook1 ; ne = yes mov ax,1 ; say success ret unhook1:push bp mov bp,sp push es push bx push cx clc mov tempax,0 ; assume failure status mov ah,getintv ; get interrupt vector 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,setintv ; 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 hooked,0 ; say not hooked 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. ; For use only by Telnet code as an internal procedure. ourtimer proc near assume ds:DGROUP, es:nothing 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,3 ; keep 2 bits, about .25 sec @18.2t/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 mov ax,DGROUP mov es,ax 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,DGROUP mov ds,ax 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. ; AH holds BAPI request code ; ES:BX is pointer to user's buffer, CX holds request count. public ktcpcom ktcpcom proc FAR ; i/o service routine assume ds:DGROUP, es:nothing push ds push ax mov ax,DGROUP ; set addressibility to our dgroup mov ds,ax pop ax cmp hooked,0 ; have we inited (hooked vectors)? je ourser7 ; e = no, report nothing test _tcpflag,2 ; is Int 8 running TCP? jz ourser8 ; z = no, opposite should never happen ourser7: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 mov kstack,sp ; remember caller's stack now mov sp,word ptr tcpstack ; move to our TCP stack mov word ptr _bapiadr,bx ; remember caller's es:bx mov word ptr _bapiadr+2,es ; (i/o buffer address) mov _bapireq,cx ; requested char count to TCP code mov _bapiret,0 ; init returned CX char count cmp ah,bapihere ; presence check? jne ourser2 ; ne = no mov ax,0af01h ; return this value jmp ourser4 ; done 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: mov bx,DGROUP ; set up es to dgroup too mov es,bx ; bx is not needed at this time ASSUME DS:DATA push ds mov bx,seg data ; address main body mov ds,bx mov es:_kserver,0 ; assume not a server test flags.remflg,dserver ; Server mode? jz ourser3a ; z = no mov es:_kserver,1 ; say being a server ourser3a: push ax mov al,tcpdebug ; debug option mov es:_kdebug,al pop ax pop ds ; return ds to dgroup ASSUME DS:DGROUP, ES:DGROUP xchg ah,al ; put BAPI function code in al xor ah,ah push ax ; setup call frame call _serial_handler ; a near call, _serial_handler(ax) ; reg ax has return status add sp,2 ; clean stack mov cx,DGROUP ; local addressing again mov ds,cx mov cx,_bapiret ; CX has count of chars returned 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. ; For use only by Telnet code as an internal procedure. ; Return CX as number of bytes delivered to Kermit main body. oursmsg proc near assume ds:DGROUP, es:nothing mov cx,_msgcnt jcxz ourser3 ; z = no msgs push es ; debug to log file mov bx,seg tloghnd ; transaction log handle segment mov es,bx mov bx,es:tloghnd ; transaction log handle pop es cmp bx,-1 ; transaction log open? je oursmsg4 ; e = no, no file writing mov dx,offset DGROUP:_msgbuf ; ds:dx is source buffer mov ah,write2 ; write cx bytes with handle in bx int dos sub _msgcnt,ax ; deduct quantity written xor cx,cx ; count of bytes returned to caller jmp short oursmsg3 ; all done oursmsg4: ; debug to transaction log file cmp cx,_bapireq ; longer than request? jbe oursmsg1 ; be = no mov cx,_bapireq ; do this much now oursmsg1: push cx push es mov si,DGROUP mov ds,si mov si,offset DGROUP:_msgbuf ; whence it comes les di,_bapiadr ; where it goes cld rep movsb ; copy Telnet buffer to main body pop es 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 ; le = none push cx push es mov si,DGROUP mov es,si mov si,offset DGROUP:_msgbuf ; whence it comes mov di,si add si,cx ; number bytes read mov cx,_msgcnt ; number of bytes remaining cld rep movsb pop es pop cx oursmsg3:xor ax,ax ; return status of success ret ; cx has delivered byte count 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 0 ; tcpttbuf db 32 dup (0),0 ; term-type-override buffer ; tcpmss dw 1500 ; ; tcpdata dw offset tcpaddress ; externally visible far pointers ; dw offset tcpsubnet + 2 ; dw offset tcpdomain + 4 ; dw offset tcpgateway + 6 ; dw offset tcpprimens + 8 ; dw offset tcpsecondns + 10 ; dw offset tcphost + 12 ; dw offset tcpbcast + 14 ; dw offset tcpport + 16 ; dw offset tcppdint + 18 ; dw offset tcpttbuf + 20 ; dw offset tcpbtpserver + 22 ; dw offset tcpnewline + 24 ; dw offset tcpdebug + 26 ; dw offset tcpmode + 28 ; dw offset tcpmss + 30 ; ; Open a TCP/IP Telnet connection. Returns -1 if failure or if success it ; returns the small int session ident code. Creates a new session; use ; ktcpswap to reactivate existing sessions. public ktcpopen ktcpopen 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 si,offset tcpaddress ; 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,offset tcpsubnet ; subnet mask mov di,offset DGROUP:_knetmask mov cx,16 start6: lodsb stosb or al,al loopne start6 xor al,al stosb mov si,offset tcpdomain ; domain mov di,offset DGROUP:_kdomain mov cx,32 start7: lodsb stosb or al,al loopne start7 xor al,al stosb mov si,offset tcpgateway ; gateway mov di,offset DGROUP:_kgateway mov cx,16 start8: lodsb stosb or al,al loopne start8 xor al,al stosb mov si,offset tcpprimens ; primary nameserver mov di,offset DGROUP:_kns1 mov cx,16 start9: lodsb stosb or al,al loopne start9 xor al,al stosb mov si,offset tcpsecondns ; secondary nameserver mov di,offset DGROUP:_kns2 mov cx,16 start10:lodsb stosb or al,al loopne start10 xor al,al stosb mov si,offset tcphost ; remote host IP mov di,offset DGROUP:_khost mov cx,60 start11:lodsb stosb or al,al loopne start11 xor al,al stosb mov si,offset tcpbcast ; IP broadcast mov di,offset DGROUP:_kbcast mov cx,16 start12:lodsb stosb or al,al loopne start12 xor al,al stosb mov ax,tcpport ; port mov es:_kport,ax mov ax,tcppdint ; Packet Driver Interrupt mov es:_kpdint,ax ; 0 means scan mov si,offset tcpttbuf ; 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 al,tcpdebug ; debug-Options mov es:_kdebug,al mov al,tcpmode ; mode mov es:_ktnmode,al mov ax,tcpmss ; MSS override mov es:_ktcpmss,ax mov si,portval mov al,[si].ecoflg ; mainline SET echo flag mov es:_echo,al ; init Options to this value 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 start16 ; z = no mov es:_kserver,1 ; say being a server (do Listen) start16:mov ax,flags.vtflg ; get terminal type index mov es:_kterm,ax start20:mov bx,portval mov al,[bx].ecoflg ; get mainline SET echo flag mov es:_echo,al ; init Telnet echo status 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 ; cold vs warm start mov word ptr kstack,sp ; store Kermit's stack ptr cmp word ptr tcpstack+2,0 ; defined setup yet? je start1 ; e = no, get stack segment mov ax,word ptr tcpstack ; set sp to existing TCP sp mov sp,ax ; warm restart jmp short start2 start1: mov word ptr tcpstack+2,ax ; set TCP stack seg to DGROUP mov word ptr tcpstack,bx ; cold start mov sp,bx ; new TCP stack pointer, DGROUP based start2: mov bp,sp ; preset this as insurance or _tcpflag,1 ; say this is running TCP code call _tnmain ; call the C code mov sp,word ptr kstack ; restore for Kermit's main stack ASSUME ES:DATA mov bx,data ; main Kermit data segment mov es,bx mov bx,_tcp_status ; status from msntnd.c mov es:tcp_status,bx ; return tcp_status to main body mov bx,_kpdint ; report back Packet Driver Int mov es:tcppdint,bx ; store value in main data seg ASSUME ES:NOTHING and _tcpflag,not 1 ; finished running tcp code 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, status in AX ktcpopen endp ; Close session whose session ident is in register AL. If AL holds -1 ; then shut down all sessions and shutdown Telnet. Returns ident of next ; active session (cyclic from the current session ident) or -1 if none ; remains active. public ktcpclose ktcpclose 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 cx,dgroup ; set addressibility to dgroup mov ds,cx mov es,cx mov kstack,sp ; remember Kermit's main sp cmp word ptr tcpstack+2,0 ; have setup stack? jne ktcpclo4 ; ne = yes mov ax,-1 ; set failure status jmp short ktcpclo6 ; e = no, skip this routine ktcpclo4:or _tcpflag,1 ; say we are running TCP code mov cx,word ptr tcpstack ; set sp to TCP sp mov sp,cx mov bp,sp ; preset this as insurance cbw ; sign extend cmp al,-1 ; close all sessions and TCP/IP? je ktcpclo5 ; e = yes push ax ; AL = session number call _session_close ; close this session add sp,2 ; returns status in AL jmp short ktcpclo6 ; common completion code ktcpclo5: ; forceful shutdown of TCP/IP Telnet xor ax,ax push ax ; tnexit(0) setup call _tnexit add sp,2 ; returns status in AX ktcpclo6:cbw ; sign extend mov sp,kstack mov _tcpflag,0 ; no one is running the TCP code 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 ktcpclose endp ; Change active sessions. Enter with AL holding desired session ident. ; Returns -1 if failure, else returns active session ident. public ktcpswap ktcpswap 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 cx,dgroup ; set addressibility to our dgroup mov ds,cx mov es,cx cmp word ptr tcpstack+2,0 ; have setup stack? jne ktcpswap1 ; ne = yes mov ax,-1 ; set failure status jmp short ktcpswap2 ; fail ktcpswap1:or _tcpflag,1 ; say we are running TCP code mov kstack,sp ; remember Kermit's main sp mov sp,word ptr tcpstack ; move to our TCP stack mov bp,sp ; preset this as insurance cbw ; sign extend now push AX ; new session number call _session_change add sp,2 ; pop argument, status is in AX mov _tcpflag,0 ; no one is running the TCP code mov sp,kstack ktcpswap2: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 ktcpswap endp ; Copies TCP/IP info from Telnet space to main Kermit space via table of ; pointers tcpdata (in segment data, file mssset.asm). ; For use only by Telnet code as an internal procedure. public _readback _readback proc near assume ds:dgroup, es:nothing push bp mov bp,sp push si push di push es mov si,offset dgroup:_kmyip push si push si ; argument call _strlen ; get length of string add sp,2 ; ax has string length pop si ASSUME ES:DATA mov di,DATA mov es,di mov di,offset tcpaddress ; offset of the string mov cx,ax ; length cld rep movsb xor al,al stosb ; terminator mov si,offset dgroup:_knetmask mov di,offset tcpsubnet mov cx,17 rep movsb stosb ; terminator mov si,offset dgroup:_kdomain mov di,offset tcpdomain mov cx,32 rep movsb stosb ; terminator mov si,offset dgroup:_kgateway mov di,offset tcpgateway mov cx,17 rep movsb stosb ; terminator mov si,offset dgroup:_kns1 mov di,offset tcpprimens mov cx,17 rep movsb stosb ; terminator mov si,offset dgroup:_kns2 mov di,offset tcpsecondns mov cx,17 rep movsb stosb ; terminator mov si,offset dgroup:_khost mov di,offset tcphost mov cx,60 rep movsb stosb ; terminator mov di,offset tcpbtpserver mov cx,16 mov si,offset dgroup:_kbtpserver rep movsb stosb ; terminator mov di,offset tcpbtpkind mov al,_bootmethod stosb pop es pop di pop si 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. ; For use only by Telnet code as an internal procedure. 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 ifndef no_terminal cmp ttyact,0 ; acting as a Terminal? je kecho2 ; e = no call dword ptr ftogmod ; toggle mode line call dword ptr ftogmod ; and again endif ; no_terminal kecho2: pop ax pop si pop es pop ds pop bp ret _kecho endp ; Track Telnet dobinary variable into Kermit main body. ; Call this each time Telnet options change dobinary. ; For use only by Telnet code as an internal procedure. public _kmode _kmode proc near assume ds:data, es:nothing push bp mov bp,sp push ds push ax push bx mov ax,data ; Kermit main data segment mov ds,ax mov al,[bp+4+0] ; get Telnet _dobinary variable mov tcpmode,al ; update main body pop bx pop ax pop ds pop bp ret _kmode endp ; Get current terminal emulation screen lines and columns public _get_kscreen _get_kscreen proc near assume ds:data, es:DGROUP push ds push es mov ax,seg data ; address main body mov ds,ax mov ax,DGROUP mov es,ax mov al,ds:crt_lins ; get display height mov es:_kterm_lines,al mov al,ds:crt_cols ; get display width mov es:_kterm_cols,al pop es pop ds ret _get_kscreen endp ; Report s->rto to tcp_rto variable for mainline Kermit public _krto _krto proc near ASSUME ES:DATA push bp mov bp,sp push es mov ax,seg DATA mov es,ax mov ax,[bp+4] ; get s->rto mov es:tcp_rto,ax ; report to mainline code pop es pop bp ret ASSUME ES:NOTHING _krto endp _TEXT ends end