home *** CD-ROM | disk | FTP | other *** search
- NAME MSNPDI
- ; File MSNPDI.ASM
- ; Packet Driver and ODI interface
- ;
- ; Copyright (C) 1985, 1993, 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.
- ;
- ; Permission is granted to use this file as a guide in developing commercial
- ; products. If substantial portions are used crediting the source is
- ; recommended.
- ;
- ; Written by Joe R. Doupnik, Utah State University, Logan Utah 84322
- ; jrd@cc.usu.edu, jrd@usu.Bitnet.
- ;
- ; Packet Driver reference:
- ; "PC/TCP Version 1.09 Packet Driver Specification", FTP Software, Inc.,
- ; September-14-1989.
- ;
- ; ODI references:
- ; "Open Data-Link Interface Developer's Guide for DOS Network Layer Protocol
- ; Stacks", Novell Inc, document number 100-001218-001 (1992, but no printed
- ; date).
- ; "Open Data-Link Interface Developer's Guide for NetWare v3.1x Server
- ; Driver Protocol Stacks", Novell Inc, document number 100-001196-00, v1.0,
- ; 19 Sept 1991.
- ; "Open Data-Link Interface LAN Driver Developer's Guide for DOS", Novell Inc,
- ; document number 107-000010-001, Revision i, 13 Nov 1990.
- ;
- ; C language interface presumes the Small memory model and Microsoft C.
- ; Assembler is MS MASM v6.
- ;
- ; These procedures interface between ODI or a Packet Driver and the main
- ; protocol stack to both send and receive packets. The upper levels provide
- ; and receive packets framed as Ethernet_II (Blue Book/DIX), and receive
- ; ARP information particular to the physical frames involved. Conversion of
- ; this internal form to the actual framing method on the wire is done by ODI.
- ; The receive buffer is external to this routine. Received packets are linked
- ; into the buffer on an order of arrival basis (and sized to fit). High level
- ; reception has to poll the receive buffer queue. Transmitted packets are
- ; operated with a single external buffer, and sending blocks until the lower
- ; level driver material is ready for us. Initialization, status, attachment,
- ; and disengagment procedures are here.
- ; External int kpdint is used by pdinit() to select between Packet Driver
- ; and ODI interfaces. Call pdinit() to initialize the system, then call
- ; pdaccess() to register each desired frame TYPE, call pdclose() to release
- ; each frame TYPE.
- ; Packet senders call pkt_send() directly.
- ; Packet receivers examine the external packet buffer for packets.
- ; ARP information is returned in external ints arp_hardware (hardware ARP
- ; type code) and MAC_len (length of MAC address, in bytes). See table below
- ; for the possible pairs.
- ; Packet Driver usage is limited to Ethernet_II/DIX and SLIP. ODI usage is
- ; at least Ethernets, Token Ring, Arcnet, and others untested here.
- ;
- ; Edit history
- ; 27 August 1992 version 3.13
- ; Last edit
- ; 22 May 1993
-
- getintv equ 35h ; DOS get interrupt vector to es:bx
- dos equ 21h
- lf equ 0ah
- fopen equ 3dh ; DOS file operations
- fclose equ 3eh
- fread equ 3fh
-
- pdgetinfo equ 1 ; Packet Driver functions
- pd_access equ 2
- pd_release equ 3
- pd_send equ 4
- pd_get_address equ 6
- eaddr_len equ 6 ; length of an Ethernet address
- ETH_MSS equ 1046 ; Correlate with msntcp.h
- IF_EII equ 1 ; Ethernet II interface type
- IF_SLIP equ 6 ; SLIP interface type, RFC1055
-
- link struc ; receiver buffer link structure
- flag db 0 ; buffer use flag
- bufnum db 0 ; buffer write sequence number
- count dw 0 ; count of bytes to follow
- link ends
- linksize equ 4 ; bytes in link structure
-
- ; Novell ODI material, based on LSL v1.2.
- ; Most of these header structures were taken from Novell file ODI.INC,
- ; and parts have been tailored for Kermit. Information on the "new" item in
- ; the lookahead structure is compliments of Novell, private correspondence.
-
- ; Event Control Block Structure
- ECBstruct struc
- nextlink dd 0 ; leave intact
- prevlink dd 0 ; leave intact
- status dw 0 ; general status
- esr dd 0 ; addr of event service routine
- stackid dw 0 ; protocol stack ident
- protid db 6 dup (0) ; sending only
- boardnum dw 0 ; sending, MILD board number
- immaddr db 6 dup (0) ; MAC destination address
- driverws db 4 dup (0) ; their work space
- protocolws dw 4 dup (0) ; our work space
- datalen dw 0 ; total length of sent buffer
- fragcount dw 1 ; number of buffer pieces
- frag1addr dw 0,0 ; seg:offset of first buffer
- frag1len dw 0 ; length of first buf frag
- ECBstruct ends ; 26 words
-
- ; Look Ahead Structure
- LookAheadStruc struc
- LMediaHeaderPtr dd 0 ; pointer to MAC header
- LookAheadPtr dd 0 ; pointer to pkt Data
- LookAheadLen dw 0 ; length of pkt Data field
- LProtID db 6 dup (0) ; protocol ident
- LBoardNum dw -1 ; logical board of rcv'd pkt
- DataLookAheadDataSize dd 0 ; new field, exists if bit 7 of the
- ; Driver's Configuration Table Mode Flags is set.
- LookAheadStruc ends
-
- ; Rx Destination Address Type (First byte of ECB.DriverWS)
- ECB_DIRECT equ 00h ;Physical destination address
- ECB_MULTICAST equ 01h ;Multicast destination address
- ECB_BROADCAST equ 03h ;Broadcast destination address
-
- ; System Error Code Definitions
- LSLERR_OUT_OF_RESOURCES equ 8001h
- LSLERR_BAD_PARAMETER equ 8002h
- LSLERR_NO_MORE_ITEMS equ 8003h
- LSLERR_ITEM_NOT_PRESENT equ 8004h
- LSLERR_FAIL equ 8005h
- LSLERR_RX_OVERFLOW equ 8006h
- LSLERR_CANCELLED equ 8007h
- LSLERR_BAD_COMMAND equ 8008h
- LSLERR_DUPLICATE_ENTRY equ 8009h
- LSLERR_NO_SUCH_HANDLER equ 800ah
- LSLERR_NO_SUCH_DRIVER equ 800bh
-
- ; LSL MLID Services Function Codes
- MLIDSUP_GET_ECB equ 0
- MLIDSUP_RETURN_ECB equ 1
- MLIDSUP_DEFRAG_ECB equ 2
- MLIDSUP_SCHEDULE_AES_EVENT equ 3
- MLIDSUP_CANCEL_AES_EVENT equ 4
- MLIDSUP_GET_INTERVAL_MARKER equ 5
- MLIDSUP_DEREGISTER_MLID equ 6
- MLIDSUP_HOLD_RECV_EVENT equ 7
- MLIDSUP_START_CRITICAL_SECTION equ 8
- MLIDSUP_END_CRITICAL_SECTION equ 9
- MLIDSUP_CRITICAL_SECTION_STATUS equ 10
- MLIDSUP_SERVICE_EVENTS equ 11
- MLIDSUP_SEND_COMPLETE equ 14
- MLIDSUP_ADD_PID equ 15
- MLIDSUP_GET_STACK_ECB equ 16
-
- ; LSL Protocol Stack Services Function Codes
- PROTSUP_GET_ECB equ 0
- PROTSUP_RETURN_ECB equ 1
- PROTSUP_SCHEDULE_AES_EVENT equ 3
- PROTSUP_CANCEL_EVENT equ 4
- PROTSUP_GET_INTERVAL_MARK equ 5
- PROTSUP_REGISTER_STACK equ 6
- PROTSUP_DEREGISTER_STACK equ 7
- PROTSUP_REGISTER_DEFAULT_STACK equ 8
- PROTSUP_DEREGISTER_DEFAULT_STACK equ 9
- PROTSUP_REGISTER_PRESCAN_STACK equ 10
- PROTSUP_DEREGISTER_PRESCAN_STACK equ 11
- PROTSUP_SEND_PACKET equ 12
- PROTSUP_GET_PROTNUM_FROM_NAME equ 16
- PROTSUP_GET_PID_PROTNUM_MLIDNUM equ 17
- PROTSUP_GET_MLID_CTL_ENTRY equ 18
- PROTSUP_GET_PROTO_CTL_ENTRY equ 19
- PROTSUP_GET_LSL_STATS equ 20
- PROTSUP_BIND_STACK_TO_MLID equ 21
- PROTSUP_UNBIND_STACK_FROM_MLID equ 22
- PROTSUP_ADD_PID equ 23
- PROTSUP_RELINQUISH_CONTROL equ 24
- PROTSUP_GET_LSL_CONFIG equ 25
-
- ; LSL General Services Function Codes
- GENSERV_ALLOC_MEMORY equ 0
- GENSERV_FREE_MEMORY equ 1
- GENSERV_REALLOC_MEMORY equ 2
- GENSERV_MEMORY_STATISTICS equ 3
- GENSERV_ADD_MEMORY_TO_POOL equ 4
- GENSERV_ADD_GENERAL_SERVICE equ 5
- GENSERV_REMOVE_GENERAL_SERVICE equ 6
- GENSERV_GET_NETCFG_PATH equ 7
-
- ; LSL Configuration Table
- LSLConfigurationStructure struc
- LConfigTableMajorVer db 1
- LConfigTableMinorVer db 0
- LNumLSLRxBuffers dd 0
- LRxBufferSize dd 0 ;Buffer size NOT including ECB struc size
- LMajorVersion db 0
- LMinorVersion db 0
- LConfigTableReserved db 16 dup (0)
- LSLConfigurationStructure ends
-
- ; MLID Control Commands
- GET_MLID_CONFIGURATION equ 0
- GET_MLID_STATISTICS equ 1
- ADD_MULTICAST_ADDRESS equ 2
- DELETE_MULTICAST_ADDRESS equ 3
- MLID_SHUTDOWN equ 5
- MLID_RESET equ 6
- CREATE_CONNECTION equ 7
- REMOVE_CONNECTION equ 8
- SET_LOOK_AHEAD_SIZE equ 9
- DRIVER_POLL equ 12
-
- ; MLID Configuration Table Structure
- MLIDConfigurationStructure struc
- MSignature db 'HardwareDriverMLID',8 dup (' ')
- MConfigTableMajorVer db 1
- MConfigTableMinorVer db 11
- MNodeAddress db 6 dup (?)
- MModeFlags dw ?
- MBoardNumber dw ?
- MBoardInstance dw ?
- MMaxPacketSize dw ?
- MBestDataSize dw ?
- MWorstDataSize dw ?
- MCardLongName dd ?
- MCardShortName dd ? ; visible board name
- MFrameString dd ?
- MReserved0 dw 0 ;Must be set to 0
- MFrameID dw ?
- MTransportTime dw ?
- MRouteHandler dd ? ;Only for Token-Ring
- MLookAheadSize dw ?
- MLineSpeed dw ? ;In Mbps or Kbps
- MReserved1 db 8 dup (0) ;Must be set to 0
- MMLIDMajorVer db ?
- MMLIDMinorVer db ?
- MFlags dw ?
- MSendRetries dw ?
- MLink dd ?
- MSharingFlags dw ?
- MSlot dw ?
- MIOAddress1 dw ?
- MIORange1 dw ?
- MIOAddress2 dw ?
- MIORange2 dw ?
- MMemoryAddress1 dd ?
- MMemorySize1 dw ?
- MMemoryAddress2 dd ?
- MMemorySize2 dw ?
- MIntLine1 db ?
- MIntLine2 db ?
- MDMALine1 db ?
- MDMALine2 db ?
- MLIDConfigurationStructure ends
-
- ; MLID Config Table 'MFlags' bit definitions.
- EISA equ 01h ;EISA Bus
- ISA equ 02h ;PC/AT Bus
- MCA equ 04h ;PS/2 MCA Bus
- Len_Info equ 40h ; pkt data length in lookahead info
-
- ; MLID Config Table 'MModeFlags' bit definitions (no promiscuous mode).
- MRealDriverBit equ 0001h
- MUsesDMABit equ 0002h
- MGuaranteedDeliveryBit equ 0004h ;100% reliable on transmits
- MMulticastBit equ 0008h
- MNeedsPollingBit equ 0020h
- MRawSendBit equ 0040h
-
- ; Registered Stack structure, used during registration only
- StackInfoStruc struc
- StackNamePtr dd ip_string ; ptr to short name
- StackReceiveHandler dd ip_rcvr ; rcv routine
- StackControlHandler dd pcontrol ; control routine
- StackInfoStruc ends
-
- ; Protocol Control Commands
- GET_STACK_CONFIGURATION equ 0
- GET_STACK_STATISTICS equ 1
- BIND_TO_MLID equ 2
- UNBIND_FROM_MLID equ 3
- INFORM_MLID_DEREGISTERED equ 4
-
- ; Protocol Configuration Table
- ProtocolConfigStructure struc
- PConfigTableMajorVer db 1
- PConfigTableMinorVer db 0
- PProtocolLongName dd plname
- PProtocolShortName dd psname ; "KERMIT"
- PProtocolMajorVer db 3 ; MSK v3.13
- PProtocolMinorVer db 13
- PConfigTableReserved db 16 dup (0)
- ProtocolConfigStructure ends
-
- ; Protocol Statistics Table
- ProtocolStatStructure struc
- PStatTableMajorVer db 1
- PStatTableMinorVer db 0
- PNumGenericCounters dw 3 ; just those below
- PValidCounterMask dd 111b ; bitfield, 3 valids
- PTotalTxPackets dw 2 dup (0)
- PTotalRxPackets dw 2 dup (0)
- PIgnoredRxPackets dw 2 dup (0)
- PNumCustomCounters dw 0 ; none
- ProtocolStatStructure ends
-
- pinfo struc ; per protocol local data for ecb
- pstack dw 0 ; StackID
- pprotid db 6 dup (0) ; ProtID
- pboard dw 0 ; boardnum
- pinfo 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, ES:NOTHING
-
- _DATA SEGMENT
- extrn _pktbuf_wrote:word, _pktwnum:byte, _kpdint:word
- extrn _eth_addr:byte, _arp_hardware:word, _MAC_len:word
- extrn _mss:word
-
- pdsignature db 'PKT DRVR' ; signature of a Packet Driver
- if_type dw 0 ; interface type
- if_class db 0 ; interface class
- if_num db 0 ; interface number
- if_func db 0 ; interface functionality
- if_version dw 0 ; interface version
- iptype db 8,0 ; IP packet type
- iptypelen equ $-iptype ; length of type field for iptype
- pktbufoff dw 0 ; offset of packet buffer
- SLIPmac dw 0,0,2 ; fake SLIP dest Ethernet address
- ; ODI material
- useodi db 0 ; non-zero if using ODI for transport
- lslsig db 'LINKSUP$' ; LSL presence signature
- lslsiglen equ $-lslsig
- lslinit dd 0 ; LSL init entry point
- ; LSL entry structure, do not separate
- lslsupport dd 0 ; LSL protocol support API entry point
- lslservice dd 0 ; LSL general services API entry point
-
- mlidcont dd 0 ; MLID Control entry point
-
- ecbr_qty equ 4 ; number of receive ECB's to allocate
- maketab MACRO ; macro to make receiver ecbs
- cnt = 0
- rept ecbr_qty - 1
- ecbstruct <,,,odircmp>
- cnt = cnt + 1
- endm
- ENDM
- ecbr ecbstruct <,,,odircmp> ; first receiver ECB
- maketab ; make table of the other ecbr's
- ecbx ecbstruct <,,,odixcmp> ; one ECB for transmission
- ecbr_busy db ecbr_qty dup (0) ; our ecbr locks
- ecbx_busy db 0 ; non-zero if ECBx owned by ODI
- ecbr_num dw 0 ; temp to hold index of ecbr/ecbr_busy
- rcvtype dw 0 ; temp, holds protocol TYPE for rcv
- pconfig ProtocolConfigStructure <> ; as the name says
- pstats ProtocolStatStructure <> ; protocol statistics
- registerstk StackInfoStruc <> ; bound stack setup structure
- plname db 13,'MS-DOS Kermit',0 ; cnt, protocol stack long name, null
- protword db 8,'PROTOCOL',0 ; three NET.CFG keywords for Kermit
- psname db 6,'KERMIT',0 ; cnt, protocol stack short name, null
- bindword db 4,'BIND',0 ; third keyword
- ip_type equ 0008h ; Protocol TYPEs, big endian/net order
- arp_type equ 0608h
- rarp_type equ 3580h
- ip_string db 2,'IP',0 ; strings to match in NET.CFG file
- arp_string db 3,'ARP',0 ; to select pkt TYPEs
- rarp_string db 4,'RARP',0 ; RARP is optional
- ip_stackid pinfo <> ; StackID, Protid, boardnum
- arp_stackid pinfo <> ; for each protocol
- rarp_stackid pinfo <>
- bcast db 6 dup (0ffh) ; Broadcast address, for reception
- readnetcfg db 0 ; non-zero if have read NET.CFG
- useboard dw -1 ; board to be used, -1 = not inited
- bdname db 0,16 dup (0) ; length, 15 text, null, bound board
- tells_len db 0 ; if MLID tells pkt len for lookahead
- tempb db 0
- temp dw 0
- ; parallel lists of NetWare ODI frame types, address lengths, ARP idents
- frame_type db 2,3,4,5,6,7, 9,10,11,14,15,16,23,27,28
- num_frames equ ($ - frame_type)
- frame_adlen db 6,6,6,6,6,6, 1,6, 6, 1, 6, 6, 6, 0, 0
- hardware_type db 1,6,6,6,6,12,4,6, 6, 7, 6, 6, 0, 0, 0
- _DATA ENDS
-
- ; ODI Frame types, frame strings, length (bytes) of a MAC level address:
- ; type frame string MAC_len hardware comments
- ; 0 VIRTUAL_LAN 0 0 no MAC header used
- ; 1 LOCALTALK 6 11 Apple (Ether/Tokentalk is 802)
- ; 2 ETHERNET_II 6 1 Blue Book
- ; 3 ETHERNET_802.2 6 6 802.3 with 802.2 wrap
- ; 4 TOKEN-RING 6 4 802.5 with 802.2 wrap
- ; 5 ETHERNET_802.3 6 6 802.3 "raw", old Novell
- ; 6 802.4 6 6 Token Bus
- ; 7 NOVELL_PCN2 6 12 Novell's IBM PCnet2
- ; 8 GNET 6 4 Gateway, assumed TRN-like
- ; 9 PRONET-10 1 4 Proteon TRN-like
- ; 10 ETHERNET_SNAP 6 1 802.3 with 802.2+SNAP
- ; 11 TOKEN-RING_SNAP 6 6 802.5 with 802.2+SNAP
- ; 12 LANPAC_II 6 ? Racore
- ; 13 ISDN 6 ? telco
- ; 14 NOVELL_RX-NET 1 7 Arcnet-like
- ; 15 IBM_PCN2_802.2 6 12 IBM PCnet2 with 802.2
- ; 16 IBM_PCN2_SNAP 6 12 IBM PCnet2,802.2+SNAP
- ; 17 OMNINET/4 ? ? Corvus
- ; 18 3270_COAXA ? ? Harris
- ; 19 IP ? ? tunneled
- ; 20 FDDI_802.2 6 ?
- ; 21 IVDLAN_802.9 6 ? Commtex
- ; 22 DATACO_OSI ? ? Dataco
- ; 23 FDDI_SNAP 6 6 802.7, with 802.2+SNAP
- ; 27 SLIP 0 0 SLIP, IP over serial link
- ; 28 PPP 0 0 PPP, IP over PPP serial link
- ;
- ; ARP hardware field, from RFC 1060
- ; Type Description
- ; ---- -----------
- ; 1 Ethernet (10Mb)
- ; 2 Experimental Ethernet (3Mb)
- ; 3 Amateur Radio AX.25
- ; 4 Proteon ProNET Token Ring
- ; 5 Chaos
- ; 6 IEEE 802 Networks
- ; 7 ARCNET
- ; 8 Hyperchannel
- ; 9 Lanstar
- ; 10 Autonet Short Address
- ; 11 LocalTalk
- ; 12 LocalNet (IBM PCNet or SYTEK LocalNET)
-
- _TEXT segment
-
- pktdrvr proc near ; Packet Driver interrupt invokation
- PKTDRVI:int 60h ; Interrupt number, modified by startup code
- ret
- pktdrvr endp
-
- ; pdinit(ðeraddress)
- ; Initialize Packet Driver or ODI for use by this program. Stores Ethernet
- ; address (or MAC address). _kpdint is 0 to scan first for a Packet Driver
- ; interrupt and fall back to search for ODI, or is a number 60h..7fh to
- ; target only that PD interrupt, or is 'DO' to target only ODI. If a PD is
- ; used then _kpdint is modified to be the found interrupt value.
- ; A 6 byte MAC level address is returned for convenience, even for SLIP.
- ; If the machine is an XT or Windows enhanced mode is active then do not
- ; use the ODI code at this time (no Int 2Fh, no bridge between real and
- ; protected mode virutal machines).
- ; Returns 1 for success, 0 for failure.
-
- public _pdinit
- _pdinit proc near
- push bp
- mov bp,sp
- push es
- push si
- push di
- push ds
- mov ax,dgroup
- mov ds,ax
- mov ax,[bp+4+0] ; get offset of pktbuf
- mov pktbufoff,ax ; save locally
- mov cx,60h ; interrupt range
- cmp _kpdint,0 ; user value given for PD Int?
- je pdinit1 ; e = no
- mov cx,_kpdint ; use it
- mov _kpdint,0 ; assume no user value
- pdinit1:cmp _kpdint,'DO' ; special indicator to use ODI?
- je short pdinit2 ; do ODI
- mov ah,getintv ; get interrupt vector to es:bx
- mov al,cl ; vector number
- int dos
- mov si,offset dgroup:pdsignature ; look for signature
- push cx
- mov cx,size pdsignature ; length of string
- mov di,bx
- add di,3 ; sig starts 3 bytes from entry point
- cld
- repe cmpsb ; compare bytes
- pop cx
- je pdinit3 ; e = found a match
- cmp _kpdint,0 ; user value given?
- jne pdinit2 ; ne = yes, so fail
- inc cx
- cmp cx,80h ; at end of range?
- jna pdinit1 ; na = not yet, try another int
- ; no Packet Driver found
- pdinit2:call odichk ; see if ODI is available
- jc pdinit5 ; c = no
- mov useodi,1 ; say using ODI
- mov _kpdint,'DO' ; signal ODI via PD interrupt variable
- mov if_class,1 ; say Ethernet_II for internal work
- mov di,[bp+4+2] ; get offset of user's buffer
- mov cx,eaddr_len ; length of address provided
- mov si,offset DGROUP:SLIPmac ; get fake Ethernet address
- cld ; in case code wants it early
- push ds
- pop es
- push di
- rep movsb ; copy to user buffer
- mov cx,ecbr_qty
- mov di,offset DGROUP:ecbr_busy ; clear receive ecb busy flags
- xor al,al
- rep stosb
- pop di
- clc
- pdinit5:jmp pdret ; exit (carry set is failure)
- ; Packet Driver details
- pdinit3:mov byte ptr PKTDRVI+1,cl ; force in new PD interrupt, code mod
- mov _kpdint,cx ; remember interrupt number
- ; find Ethernet address
- mov ah,pdgetinfo ; get Packet Driver information
- mov al,0ffh
- xor bx,bx ; optional handle
- push ds ; this call changes ds and si
- push si
- call pktdrvr ; call the Packet Driver
- pop si
- pop ds
- jc pdret ; c = failure
- pdinit6:mov if_type,dx ; save details for access calls
- mov if_class,ch
- mov if_num,cl
- mov if_func,al
- mov if_version,bx
- mov ah,pd_access ; access packets
- mov al,ch ; Ethernet class
- mov bx,dx ; type
- mov dl,cl ; interface number
- mov cx,iptypelen ; type length for iptype
- mov si,offset dgroup:iptype ; address of TYPE
- mov di,cs
- mov es,di
- mov di,offset pdrcvr ; ES:DI is our Packet Driver receiver
- call pktdrvr
- jc pdret ; c = failure
- mov bx,ax ; put returned handle in BX
- mov _arp_hardware,0001h ; Type 1 hardware, Ethernet
- mov _MAC_len,6 ; 6 bytes of MAC level address
- mov ax,DGROUP ; our data segment
- mov es,ax ; segment of Ethernet address buffer
- mov di,[bp+4+2] ; get offset of user's buffer
- mov cx,eaddr_len ; length of address wanted
- cmp if_class,IF_SLIP ; interface class of SLIP?
- jne pdinit4 ; ne = no
- mov si,offset DGROUP:SLIPmac ; get fake Ethernet address
- cld
- push di ; save in case PD actually uses it
- rep movsb ; copy to user buffer
- pop di
- mov _arp_hardware,0 ; no hardware type
- mov _MAC_len,0 ; no MAC level address
- mov _mss,1006-44 ; set SLIP max frame size too
- pdinit4:mov ah,pd_get_address ; get the Ethernet address
- push bx ; save handle
- call pktdrvr ; get Ethernet address to es:di buf
- pop bx
- pushf ; save carry flag
- mov ah,pd_release ; release this Type, bx has handle
- call pktdrvr
- popf ; recover carry flag
- pdret: mov ax,1 ; return C status, 1 for success
- jnc pdret1
- xor ax,ax ; 0 for failure
- pdret1: pop ds ; success
- pop di
- pop si
- pop es
- mov sp,bp ; restore stack
- pop bp ; recover bp reg
- ret
- _pdinit endp
-
- ; int pdinfo(& int version, & int class, & int pdtype, & int number,
- ; & int functionality)
- ; Get Packet Driver pedigree
- public _pdinfo
- _pdinfo proc near
- push bp
- mov bp,sp
- push di
- push cx
- push bx
- push ax ; save al for later use
- mov di,[bp+4+0]
- mov bx,if_version
- mov [di],bx ; return version
- mov al,if_class ; class
- xor ah,ah
- mov di,[bp+4+2]
- mov [di],ax ; return as an int
- mov di,[bp+4+4]
- mov dx,if_type
- mov [di],dx ; type
- mov di,[bp+4+6]
- xor ch,ch
- mov cl,if_num
- mov [di],cx ; interface number, as an int
- pop ax ; recover al
- mov di,[bp+4+8]
- xor ah,ah
- mov al,if_func
- mov [di],ax ; functionality, as an int
- mov ax,1 ; C style exit status, 1 = success
- pop bx
- pop cx
- pop di
- pop bp
- ret
- _pdinfo endp
-
- ; int pdclose(int handle)
- ; Close a Packet Driver or ODI handle.
- ; Returns (in AX) 1 if successful, else 0.
- public _pdclose
- _pdclose proc near
- push bp
- mov bp,sp
- push bx
- mov bx,[bp+4+0] ; handle
- cmp useodi,0 ; using ODI?
- je pdclos2 ; e = no
- mov ax,bx ; get handle
- call odiunbind ; unbind from LSL and MLID
- jmp short pdclos3
-
- pdclos2:mov ah,pd_release ; release_type
- call pktdrvr
-
- pdclos3:mov ax,1 ; assume success
- jnc pdclos1 ; nc = success
- xor ax,ax ; 0 for failure
- pdclos1:pop bx
- pop bp
- ret
- _pdclose endp
-
- ; int pdaccess(char *type, int typelen, int *handle)
- ; Register access for packet TYPE with the Packet Driver or ODI
- ; Provides a handle for the TYPE.
- ; Returns 1 for success, 0 for failure.
- public _pdaccess
- _pdaccess proc near
- push bp
- mov bp,sp
- push es
- push si
- push di
- push ds
- push es
- mov ax,dgroup ; set up data segment addressibility
- mov ds,ax
- mov al,if_class ; interface class (frame)
- mov bx,if_type ; interface type (vendor)
- mov dl,if_num ; interface number (board number)
- xor dh,dh
- mov si,[bp+4+0] ; get offset of packet TYPE buffer
- mov cx,[bp+4+2] ; typelen (length of buf contents)
- cmp useodi,0 ; using ODI?
- je pdacc8 ; e = no
- mov ax,[si] ; provide TYPE
- call odibind ; Bind to a virtual board
- jc pdacc1 ; c = fail, error code in AX
- jmp short pdacc9 ; store handle returned in AX
-
- pdacc8: cmp if_class,IF_SLIP ; SLIP?
- jne pdacc3 ; ne = no
- xor cx,cx ; TYPE len = 0 means accept all types
- pdacc3: mov di,cs ; ES:DI is our Packet Driver receiver
- mov es,di
- mov di,offset pdrcvr ; local receiver
- mov ah,pd_access ; set access
- call pktdrvr
- jc pdacc1 ; c = failure
- pdacc9: mov si,[bp+4+4] ; offset of handle
- mov [si],ax ; return the handle
- pdacc1: mov ax,1 ; C level status, 1 = success
- jnc pdacc2 ; nc = success
- xor ax,ax ; 0 = failure
- pdacc2: pop es
- pop ds
- pop di
- pop si
- pop es
- pop bp
- ret
- _pdaccess endp
-
- ; int pkt_send(char *buffer, int length)
- ; returns 1 on success, 0 on failure
- ; Send a packet.
- public _pkt_send
- _pkt_send proc near
- push bp
- mov bp,sp
- push es
- push ds
- push si
- push di ; don't trust lower levels on regs
- push cx
- mov ax,dgroup ; segment of outgoing buffer
- mov ds,ax ; will be DS:SI for Packet Driver
- mov si,[bp+4+0] ; buffer's offset (seg is dgroup)
- mov cx,[bp+4+2] ; buffer's length
-
- cmp useodi,0 ; using ODI?
- je pktsen5 ; e =no, use PD
- pktsen3:cmp ecbx_busy,0 ; is ODI transmit done yet?
- je pktsen4 ; e = yes, else we can't touch it yet
- mov bx,PROTSUP_RELINQUISH_CONTROL
- call lslsupport ; give time to LSL
- jmp short pktsen3 ; wait for done
- pktsen4:call odixmt ; do LSL transmit with DS:SI and CX
- sti ; interrupts back on (xmt turns off)
- jmp short pktsen1 ; done (AX non-zero if error)
- ; Note that checking for transmission errors is not readily done with async
- ; sending, so we cross our fingers and hope for the best.
- ;
- ; Packet Driver sending
- pktsen5:mov ah,pd_send ; send packet (buffer = ds:si)
- call pktdrvr ; invoke Packet Driver
- ; common exit
- pktsen1:mov ax,1 ; return C level success (1)
- jnc pktsen2 ; nc = success
- xor ax,ax ; else C level failure (0)
- pktsen2:pop cx
- pop di
- pop si
- pop ds
- pop es
- pop bp
- ret
- _pkt_send endp
-
- ; Our Packet Driver receiver, far called only by the Packet Driver and our
- ; local ODI code (odircvr and odircmp).
- ; Packet buffer linked list -
- ; each link is db flag ; 1 = free, 2 = in use, 4 = allocated
- ; ; but not in use yet, 0 = end of buf,
- ; ; 8 = read but not freed.
- ; db _pktwnum ; sequential number of pkt written
- ; dw count ; length of data field
- ; db count dup (?) ; the allocated data field
- ; The head of the chain has a link like all others.
- ; The end of the chain has a link with flag == 0 and count = -BUFISZE
- ; to point to the beginning of the buffer (circular).
- ; Packet buffer garbage collection is done after a buffer has been
- ; transferred to us, and does so by relinking adjacent free blocks.
- ; _pktbuf_wrote is used to remember the link where the last write occurred
- ; and should be initialized to the tail link to point the next write to
- ; the beginning of the buffer.
- ; The Packet Driver and our ODI routines call this first with AX = 0 to
- ; obtain a buffer pointer in ES:DI from us (0:0 if we refuse the pkt) with
- ; CX = packet size, and again later with AX = 1 to post completion.
-
- pdrcvr proc far ; Packet Driver receiver
- or ax,ax ; kind of request (0, 1)
- jz pdrcvr1 ; z = first, get-a-buffer
- ; Second upcall, packet has xfered, DS:SI set by caller to buffer
- pushf ; save interrupt status
- cli ; interrupts off
- push ds
- push si
- push bx
- push ax ; assume DS:SI is one of our buffers
- mov ax,DGROUP
- mov ds,ax ; set ds to our data segment
- or si,si ; is it legal (from first upcall)?
- jz pdrcvr11 ; z = no, ignore this call
- sub si,linksize ; backup to link info
- cmp byte ptr [si].flag,4 ; is this buffer allocated (4)?
- jne pdrcvr8 ; ne = no, do cleanups and quit
- mov byte ptr [si].flag,2 ; flag = 2 for buffer is now ready
- mov si,pktbufoff ; start of packet buffer
- ; join contiguous free links
- pdrcvr8:mov al,[si].flag ; flags byte
- cmp al,1 ; is link free?
- jne pdrcvr10 ; ne = no, look for a free link
- pdrcvr9:mov bx,[si].count ; count (length) of this link
- mov al,[bx+si+linksize].flag; flag of following link
- cmp al,1 ; is next link free?
- jne pdrcvr10 ; ne = no, look for free link
- mov ax,[bx+si+linksize].count ; count taken from next link
- add ax,linksize ; plus the next link's info field
- add [si].count,ax ; add it to this count (merge links)
- jmp short pdrcvr9 ; re-examine this new longer link
-
- pdrcvr10:or al,al ; end of list?
- jz pdrcvr11 ; z = yes
- add si,[si].count ; look at next link (add count)
- add si,linksize ; and link info
- jmp short pdrcvr8 ; keep looking
- pdrcvr11:pop ax
- pop bx
- pop si
- pop ds
- popf
- ret
-
- pdrcvr1:pushf
- cli
- push ds ; First upcall, provide buffer ptr
- push dx ; return buffer in ES:SI
- push cx
- mov di,dgroup ; get local addressibility
- mov ds,di
- mov es,di ; packet buffer is in same group
- mov di,_pktbuf_wrote ; where last write occurred
- or di,di ; NULL?
- jz pdrcvr4 ; z = yes, write nothing
- mov dl,100 ; retry counter, breaks endless loops
- cmp [di].flag,1 ; is this link free?
- je pdrcvr5 ; e = yes, use it
-
- pdrcvr2:add di,[di].count ; point at next link (add count and
- add di,linksize ; link overhead)
- dec dl ; loop breaker count down
- or dl,dl
- jz pdrcvr4 ; z = in an endless loop, exit
- cmp [di].flag,1 ; is this link free (1)?
- je pdrcvr5 ; e = yes, setup storage
- cmp di,_pktbuf_wrote ; have we come full circle?
- jne pdrcvr2 ; ne = no, keep looking
- pdrcvr4:pop cx
- pop dx
- pop ds ; failure or buffer not available (0)
- xor ax,ax ; return what we received in ax
- xor di,di ; return ES:DI as null to reject
- mov es,di
- popf
- ret
- ; this link is free
- pdrcvr5:cmp cx,ETH_MSS+40+12 +20 ; LARGEST PACKET WE ACCEPT
- ja pdrcvr4 ; a = too large, decline it
- add cx,2 ; defense for 8/16 bit xfr mistakes
- mov ax,[di].count ; length of available data space
- cmp ax,cx ; cx is incoming size, enough space?
- jl pdrcvr2 ; l = no, go to next link
- mov [di].flag,4 ; mark link flag as being alloc'd (4)
- mov dh,_pktwnum ; write pkt sequencer number
- mov [di].bufnum,dh ; store in buffer, permits out of
- inc _pktwnum ; temporal order deliveries
- mov _pktbuf_wrote,di ; remember where we wrote last
- sub ax,cx ; allocated minus incoming packet
- cmp ax,60+linksize ; enough for new link and miminal pkt?
- jl pdrcvr6 ; l = not enough for next pkt
- mov [di].count,cx ; update space really used
- push di ; save this link pointer
- add di,linksize ; plus current link info
- add di,cx ; plus space used = new link point
- sub ax,linksize ; available minus new link info
- mov [di].flag,1 ; mark new link as free (1)
- mov [di].count,ax ; size of new free data area
- pop di ; return to current link
- pdrcvr6:add di,linksize ; point at data portion
- pdrcvr7:xor ax,ax ; return what we received in ax
- pop cx
- pop dx
- pop ds ; ES:DI is the pkt buffer address
- popf ; CX is size of requested buffer
- ret
- pdrcvr endp
-
- ; Check for XT machines or Windows enhanced mode. Return carry set if either
- ; is true, else carry clear.
- chkxtwin proc near
- mov ax,sp ; do push sp test for XT vs AT/386
- push sp ; XT pushes sp-2, AT's push old sp
- pop cx ; recover pushed value, clean stack
- xor ax,cx ; same?
- je chkxtw1 ; e = yes, AT and above
- stc
- ret ; XT, don't do Int 2fh check
- chkxtw1:push es
- mov ah,getintv ; check for valid Int 2Fh handler
- mov al,2fh ; vector 2fh
- int dos ; to es:bx
- mov ax,es
- pop es
- or ax,bx ; check if vector exists
- jnz chkxtw2 ; nz = yes
- stc
- ret
-
- chkxtw2:mov ax,1683h ; Windows 3, get current virt machine
- int 2fh
- cmp ax,1683h ; virtual machine, if any
- je chkxtw3 ; e = no Windows, ok to proceed
- stc
- ret
- chkxtw3:clc ; neither XT nor Windows enhanced mode
- ret
- chkxtwin endp
-
- ; Begin Novell ODI support routines
- ; Note that while we use Ethernet_II (6 dest, 6 source, 2 TYPE bytes) to/from
- ; internal consumers the frame format to/from ODI is in the hands of ODI.
- ; Hopefully this will permit TCP/IP operation over all supported frame types.
- ; ARP/RARP packets are sized to the frame in use.
- ;
- ; Check for LSL presence, and if present then get entry points.
- ; Returns carry set if failure, else carry clear.
- ; This procedure is closely modeled upon the Novell example.
- odichk proc near
- cmp useodi,0 ; already inited?
- je odichk0 ; e = no
- clc
- ret
- odichk0:call chkxtwin ; check for XTs or Windows
- jnc odichk5 ; nc = neither, continue
- ret ; return failure
- odichk5:push es
- mov ah,getintv ; get LSL via multiplexer interrupt
- mov al,2fh ; vector 2fh
- int dos ; to es:bx
- mov ax,es
- or ax,bx ; check if vector exists
- jnz odichk1 ; nz = yes
- pop es
- stc
- ret
-
- odichk1:mov ax,0c000h ; look at multiplexer slots c0 et seq
- push si
- push di
- odichk2:push ax
- int 2fh
- cmp al,0ffh ; is slot in use?
- pop ax
- je odichk4 ; e = yes, check for LSL being there
- odichk3:inc ah ; next slot
- or ah,ah ; wrapped?
- jnz odichk2 ; nz = no, keep looking
- pop di
- pop si
- pop es
- stc ; not found, fail
- ret
-
- odichk4:mov di,si ; es:si should point to "LINKSUP$"
- mov si,offset DGROUP:lslsig ; expected signature
- mov cx,lslsiglen ; length
- cld
- repe cmpsb ; check for signature
- jne odichk3 ; ne = no match, try next Int 2fh slot
- mov word ptr lslinit,bx ; found entry, save init entry point
- mov ax,es ; returned in es:bx
- mov word ptr lslinit+2,ax
- mov ax,ds
- mov es,ax ; get LSL main support/service addrs
- mov si,offset DGROUP:lslsupport ; address of LSL entry point array
- mov bx,2 ; request support/service entry points
- ; fills in far addresses of lslsupport and lslservice routines
- call lslinit ; call LSL initialization routine
- pop di
- pop si
- pop es
- clc ; success
- ret
- odichk endp
-
- ; Bind a protocol TYPE to an ODI virtual board.
- ; Enter with TYPE (big endian/network order) in AX.
- ; Packet reception begins immediately upon a successful bind.
- ; Uses NET.CFG if information is available.
- ; Obtain StackID (our ident to the LSL), ProtID (ident of LSL's decoder),
- ; and boardnumber (the logical board), then bind to start reception. Do for
- ; one of our protocols.
- ; Returns PD handle (TYPE) in AX and carry clear upon success, else carry set.
- odibind proc near
- push ax
- push bx
- push si
- push di
- push es
- mov bx,DGROUP
- mov es,bx
- cmp ax,ip_type ; IP, 0x0008h?
- jne odibind1 ; ne = no
- mov ax,offset DGROUP:ip_string ; put IP string in request
- mov bx,offset ip_rcvr ; set address of receiver esr
- mov di,offset DGROUP:ip_stackid ; set address of stackid struc
- jmp short odibind3
-
- odibind1:cmp ax,arp_type ; ARP, 0x0608?
- jne odibind2 ; ne = no
- mov ax,offset DGROUP:arp_string
- mov bx,offset arp_rcvr
- mov di,offset DGROUP:arp_stackid
- jmp short odibind3
-
- odibind2:cmp ax,rarp_type ; RARP, 0x3580?
- je odibind2a ; e = yes
- jmp odibindx ; ne = no, fail
- odibind2a:mov ax,offset DGROUP:rarp_string
- mov bx,offset rarp_rcvr
- mov di,offset DGROUP:rarp_stackid
-
- odibind3:mov word ptr registerstk.StackNamePtr,ax ; insert ptr to string
- mov word ptr registerstk.StackReceiveHandler,bx ; setup esr addr
-
- ; Note: to use Prescan or Default registrations delete StackNamePtr & StackID.
- ; StackID is not used with these latter methods, and their reception begins
- ; at registration rather than at bind (so this area would be redesigned).
- mov bx,PROTSUP_REGISTER_STACK ; register the protocol by name
- mov si,offset DGROUP:registerstk ; registration form pointer
- push di ; save ptr to xxx_stackid storage
- call lslsupport ; call LSL with the address in es:si
- pop di
- jz odibind3a ; z = success
- jmp odibindx ; nz = failure
- odibind3a:mov [di].pstack,bx ; save returned StackID (LSL's handle
- ; for our protocol stack)
- cmp readnetcfg,0 ; have read NET.CFG for BIND info?
- jne odibind4 ; ne = yes
- mov useboard,-1 ; clear board-to-use word
- call getbind ; find Kermit's bind board in NET.CFG
- inc readnetcfg ; say have read the file
- cmp word ptr bdname,256*'#'+2 ; is board name #<digit>?
- jne odibind4 ; ne = no, assume regular driver name
- mov al,bdname+2 ; get ascii digit
- sub al,'1' ; remove ascii bias (external=1 based)
- xor ah,ah ; but we are zero based internally
- cmp al,8 ; arbitrary limit of 8 boards
- ja odibind4 ; a = out of range, ignore value
- mov useboard,ax ; and make this the board number
- mov bdname,0 ; and don't use bdname as a name
- odibind4:mov [di].pboard,0 ; assume board zero to start loop
- mov ax,useboard ; board to be used, if any
- or ax,ax ; boards 0 and up are legal
- jl odibind5 ; l = no board found yet, search
- mov [di].pboard,ax ; specify board, get ProtID
-
- odibind5:mov bx,PROTSUP_GET_MLID_CTL_ENTRY ; get MLID control entry
- mov ax,[di].pboard ; for this board
- push di
- call lslsupport ; call LSL for the address to es:si
- pop di
- mov word ptr mlidcont,si
- mov word ptr mlidcont+2,es ; MLID control routine
- jz odibind7 ; z=success, have a board to work with
- cmp ax,LSLERR_NO_MORE_ITEMS ; out of items?
- je odibind5a ; e = yes, no more boards
- cmp ax,LSLERR_ITEM_NOT_PRESENT ; other boards may exist?
- je odibind7 ; e = yes
- odibind5a:jmp odibindx ; fail
-
- odibind7:mov bx,PROTSUP_GET_PID_PROTNUM_MLIDNUM ; get ProtID from StackID
- mov ax,[di].pstack ; StackID
- mov cx,[di].pboard ; and assumed board number
- mov si,dgroup
- mov es,si ; set es:di to the ProtID buffer
- lea si,[di].pprotid ; in our storage slot per protocol
- push di
- call lslsupport ; ask LSL for the ProtID string
- pop di ; to that 6-byte buffer
- jz odibind9 ; z = success, found a recognizer
- cmp useboard,0 ; has a board been pre-identified?
- jge odibind5a ; ge = yes, so the matchup failed
- inc [di].pboard ; next board
- jmp short odibind5 ; keep looking for a board
-
- odibind9:mov bx,GET_MLID_CONFIGURATION ; get MLID config ptr to es:si
- mov ax,[di].pboard
- call mlidcont ; call MLID control routine
- jnz odibindx ; nz = failure
- cmp bdname,0 ; was a board name bound via BIND?
- je odibin10 ; e = no, don't check on it
- push es ; save pointer to MLID config table
- push di
- push si
- les di,es:[si].MCardShortName ; get short name of this board
- lea si,bdname ; desired board name string
- mov cl,bdname ; length of desired board name
- inc cl ; include length byte
- xor ch,ch
- cld
- repe cmpsb ; compare len,string for both
- pop si
- pop di
- pop es
- je odibin10 ; e = found desired board
- inc [di].pboard ; try next board
- jmp short odibind5 ; keep looking for the desired board
-
- odibin10:mov ax,[di].pboard ; get current board number
- mov useboard,ax ; remember for next protocol
- mov ax,es:[si].MWorstDataSize ; max header, leaving this size
- sub ax,20+20+4 ; minus IP and TCP header
- cmp ax,ETH_MSS ; smaller than our default?
- jae odibin10a ; ae = no, stay with our default
- mov _mss,ax ; set new operational value
- odibin10a:mov bx,es:[si].MFrameID ; frame ident, for get_hwd
- call get_hwd ; get hardware specifics
- or bx,bx ; returned _MAC_len, if any
- jnz odibin11 ; nz = found match
- mov bx,6 ; else default to 6 bytes
- odibin11:push es
- push si ; save config pointer
- lea si,es:[si].MNodeAddress ; point to address in config struct
- push ds ; save ds
- push di
- mov di,offset DGROUP:_eth_addr; where our MAC address is stored
- mov ax,ds
- mov cx,es
- mov es,ax
- mov ds,cx
- cld
- mov cx,bx ; MAC address length, bytes
- rep movsb ; copy MAC address to global array
- pop di
- pop ds
- pop si ; recover configuration table pointer
- pop es
- mov tells_len,0 ; presume no lookahead data length
- test es:[si].MFlags,Len_Info ; capas bit for length provided (new)
- jz odibin12 ; z = does not provide
- inc tells_len ; say provides length
-
- odibin12:mov bx,PROTSUP_BIND_STACK_TO_MLID ; Bind stack to MLID
- mov ax,[di].pstack ; StackID
- mov cx,[di].pboard ; board number
- call lslsupport ; bind our protocol stack to board
- jnz odibindx ; nz = failure
- pop es ; received packets can interrupt now
- pop di
- pop si
- pop bx
- pop ax
- clc
- ret
- odibindx:pop es
- pop di
- pop si
- pop bx
- pop ax
- stc ; say failure
- ret
- odibind endp
-
- ; Worker for odibind. Find NET.CFG, extract name of board driver from pair of
- ; lines reading as below (Protocol must be in column 1, bind must be indented)
- ; Protocol Kermit Kermit's main section header
- ; bind <board_driver_name> indented, without the <> signs
- ;or
- ; Protocol Kermit
- ; bind #<digit> selects DOS driver load order (from 1)
- ;
- ; Examples -
- ; Protocol Kermit
- ; bind exos
- ;or
- ; Protocol Kermit
- ; bind #2
- ; and elsewhere there is the board driver section:
- ; Link Driver exos
- ;
- ; If found put the board driver name in array bdname, as length byte, string,
- ; then a null. If not found make length byte bdname be zero. We treat NET.CFG
- ; as case insensitive.
- ; Unless we use the special Kermit section then LSL will assign to us the
- ; first board loaded by DOS supporting the frame kind of our protocol.
- ; Link Driver section line "Protocol name type frame" simply associates a
- ; frame kind with the name and type, but not with a board. L.D. section line
- ; frame <frame kind> attaches that frame kind to the board, if it fits.
- ; Kermit uses "name" in the above line to pinpoint a protocol, not a board.
- getbind proc near
- mov bdname,0 ; clear board name length
- push ds
- mov bx,GENSERV_GET_NETCFG_PATH ; get fully formed NET.CFG name
- call lslservice ; from LSL general services to ds:dx
- jz getbin1 ; z = success
- pop ds ; fail
- ret
- getbin1:mov ah,fopen ; open file NET.CFG
- mov al,40h ; for reading, deny none
- int dos ; returns file handle in ax
- pop ds
- mov temp,ax ; save handle for getbyte
- jnc getbin2 ; nc = success
- ret ; carry set for failure
-
- getbin2:mov bx,1 ; subscript, at start of a line
-
- getbin3:call getbyte ; read a byte, uppercased
- jnc getbin4 ; nc = success
- ret ; c = end of file
- getbin4:cmp protword[bx],al ; compare to "PROTOCOL"
- jne getbin5 ; ne = failure, scan for end of line
- inc bx
- cmp bl,protword ; length, matched all bytes?
- jbe getbin3 ; be = no, match more
- jmp short getbin6 ; ae = yes, next phrase
- ret ; fail out
-
- getbin5:cmp al,LF ; end of a line?
- je getbin2 ; e = yes, scan for PROTOCOL again
- call getbyte
- jnc getbin5 ; keep consuming line material
- ret ; fail out at end of file
- ; Short Name following "PROTOCOL"
- getbin6:call getbyte ; get separator char, discard
- jnc getbin7
- ret ; c = eof
- getbin7:call getbyte ; read short name of protocol
- jnc getbin7a ; nc = text
- ret ; return on eof
- getbin7a:cmp al,' ' ; white space?
- jbe getbin7 ; be = yes, stay in this state
- mov bx,1 ; subscript
- getbin8:cmp psname[bx],al ; compare to our protocol short name
- jne getbin5 ; ne = failure, scan for end of line
- cmp bl,psname ; matched all bytes?
- jae getbin9 ; ae = yes, next phrase
- inc bx
- call getbyte ; get next byte to match
- jnc getbin8 ; nc = not eof yet
- ret
-
- getbin9:call getbyte ; go to next line, enforce whitespace
- jc getbin20 ; c = eof
- cmp al,LF ; end of a line?
- jne getbin9 ; ne = no, scan for end of line
- call getbyte ; look for whitespace
- jc getbin20 ; c = eof
- cmp al,'#' ; comment line?
- je getbin9 ; e = yes, get next line
- cmp al,' ' ; required whitespace?
- ja getbin5 ; a = no, start over
-
- getbin10:call getbyte ; look for keyword "BIND"
- jc getbin20
- cmp al,' ' ; white space?
- jbe getbin10 ; be = yes, stay in this state
- mov bx,1 ; subscript
- getbin11:cmp bindword[bx],al ; compare to "BIND"
- jne getbin5 ; ne = failure, start over
- cmp bl,bindword ; matched all bytes?
- jae getbin12 ; ae = yes, next phrase
- call getbyte
- jc getbin20 ; c = eof
- inc bx
- jmp short getbin11 ; keep reading
-
- getbin12:call getbyte ; skip white space before board name
- jc getbin20
- cmp al,' ' ; white space?
- jbe getbin12 ; be = yes, skip it
-
- getbin13:mov bl,bdname ; board name, length byte, starts at 0
- xor bh,bh
- inc bl
- mov bdname,bl ; update length of board driver name
- xor ah,ah ; get a null
- mov word ptr bdname[bx],ax ; store as board short name,null
- cmp bx,15 ; legal limit on short name?
- jbe getbin14 ; be = ok
- mov bdname,ah ; illegal, clear board name length
- jmp getbin15 ; and quit
- getbin14:call getbyte
- jc getbin20 ; reached eof, is ok
- cmp al,' ' ; usable text?
- ja getbin13 ; a = yes, else stop storing name
- getbin15:call getbyte ; read to eof so file is closed
- jnc getbin15 ; nc = got a char
- getbin20:ret
- getbind endp
-
- ; Worker for getbind. Delivers one byte per call from NET.CFG, upper cased.
- ; Returns carry set and NET.CFG file closed at end of file.
- ; Temp has NET.CFG file handle, tempb is our one byte buffer for disk i/o.
- getbyte proc near
- mov dx,offset tempb ; ds:dx points to start of buffer
- mov ah,fread ; read from file to buffer
- mov cx,1 ; this many bytes
- push bx
- mov bx,temp ; get file handle
- int dos
- pop bx
- jc getbyt2 ; c = failure
- cmp ax,1 ; got the single byte?
- jb getbyt2 ; b = no, failure
- mov al,tempb ; return read byte
- cmp al,'z' ; in lower case range?
- ja getbyt1 ; a = no
- cmp al,'a' ; in lower case range?
- jb getbyt1 ; b = no
- and al,not 20h ; lower to upper case
- getbyt1:clc ; carry clear for success
- ret ; return char in AL
- getbyt2:push bx
- mov bx,temp ; file handle
- mov ah,fclose ; close the file
- int dos
- pop bx
- stc ; say EOF or other failure
- ret
- getbyte endp
-
- ; Worker for odibind.
- ; Enter with BX holding Novell frame type from the MLID configuration table.
- ; Set _arp_hardware and _MAC_len and return BX holding _MAC_len value, else
- ; if frame is not supported return BX = 0. These two values are needed by the
- ; ARP functions. This list searching method is to accomodate the ever
- ; expanding quantity of frame types appearing with ODI; we deal with those we
- ; understand (sic).
- get_hwd proc near
- push es
- push di
- mov ax,DGROUP
- mov es,ax
- mov al,bl ; get frame value (MLID config)
- xor bx,bx ; prepare no-match return value
- mov di,offset frame_type ; list to search
- mov cx,num_frames ; number of elements in the list
- cld
- repne scasb ; byte search
- jne get_hwd1 ; ne = no match, fail
- sub di,offset frame_type+1 ; make di be an index along the list
- mov al,hardware_type[di] ; ARP/RARP hardware type ident
- xor ah,ah ; return in local (host) order
- mov _arp_hardware,ax ; hardware type for ARP/RARP pkts
- mov bl,frame_adlen[di] ; array of MAC lengths for frame types
- xor bh,bh
- mov _MAC_len,bx ; save MAC address length (1..6 bytes)
- pop di
- pop es
- ret
- get_hwd1:mov _arp_hardware,bx ; hardware type 0 for ARP/RARP pkts
- mov _MAC_len,bx ; save MAC address length (0 bytes)
- pop di
- pop es
- ret ; return _MAC_len in BX
- get_hwd endp
-
- ; Unbind a protocol TYPE from an ODI virtual board
- ; Enter with protocol TYPE (net order) in AX, return carry set if failure.
- ; The TYPE is used as our handle to the application.
- ; Prescan and Default methods call lslsupport with the board number in AX
- ; rather than StackID and use matching PROTSUP_DEREGISTER_* code.
- odiunbind proc near
- cmp ax,ip_type ; IP, 0x0008h?
- jne odiunb1 ; ne = no
- mov ax,ip_stackid.pstack ; StackID
- jmp short odiunb3
-
- odiunb1:cmp ax,arp_type ; ARP, 0x0608?
- jne odiunb2 ; ne = no
- mov ax,arp_stackid.pstack
- jmp short odiunb3
-
- odiunb2:cmp ax,rarp_type ; RARP, 0x3580?
- jne odiunb4 ; ne = no
- mov ax,rarp_stackid.pstack
-
- odiunb3:mov bx,PROTSUP_DEREGISTER_STACK ; deregister stack (StackID in AX)
- call lslsupport ; stops reception now
- jnz odiunb4 ; nz = failure
- clc ; success
- ret
- odiunb4:stc ; failure
- ret
- odiunbind endp
-
- ; ODI receive interrupt handler, for use only by the LSL.
- ; Called with DS:DI pointing to lookahead structure, interrupts are off.
- ; Returns ES:SI pointing at ECB, AX = 0 if we want pkt, AX = 8001h if decline.
- ; There are three of these, one each for IP, ARP, and RARP. All have the
- ; same calling convention and all jump to odircv to do the real work.
- ; The length of the arriving packet is available if the MLID supports the
- ; new (mid-May 1992) capability, our "tells_len"; otherwise we make an
- ; intelligent guess based on the protocol header. These entry points can be
- ; called multiple times before receive-completion, and likely will be, so we
- ; use several ecb's to accept requests.
- ip_rcvr proc far
- push bx
- push cx
- push di
- push ds
- mov cx,ds ; DS:DI from LSL
- mov es,cx ; use ES for LSL items
- mov ax,DGROUP ; set DS to our data segment
- mov ds,ax
- push es
- push si
- cmp tells_len,0 ; have data length available?
- je ip_rec1 ; e = no
- les si,es:[di].DataLookAheadDataSize ; ptr to what it says
- mov cx,word ptr es:[si] ; get length of data field
- add cx,4 ; for overzealous board transfers
- pop si
- pop es
- jmp far ptr odircv
-
- ip_rec1:les si,es:[di].LookAheadPtr ; point at data lookahead ptr
- mov cx,word ptr es:[si+2] ; IP pkt header, length word
- cmp byte ptr es:[si],45h ; validate IP pkt kind (ver/hlen)?
- pop si
- pop es
- jne ip_rcvr1 ; ne = invalid, decline
- xchg ch,cl ; net to local order
- add cx,14+8 ; our MAC level addressing + 8 safety
- ip_rec2:mov ax,ip_stackid.pstack ; StackID for ecb structure
- mov rcvtype,ip_type ; store protocol TYPE int
- cmp cx,ETH_MSS+40+12+20 ; LARGEST ACCEPTABLE PKT
- jbe odircv ; be = acceptable length
-
- ip_rcvr1:add pstats.PIgnoredRxPackets,1 ; update ODI statistics counter
- adc pstats.PIgnoredRxPackets+2,0
- mov ax,LSLERR_OUT_OF_RESOURCES ; decline the packet
- or ax,ax ; set Z flag to match AX
- pop ds
- pop di
- pop cx
- pop bx
- ret
- ip_rcvr endp
-
- ; RARP protocol receive service routine, similar to ip_rcvr.
- rarp_rcvr proc far
- push bx
- push cx
- push di
- push ds
- mov cx,ds ; DS:SI from LSL
- mov es,cx
- mov ax,DGROUP ; set DS to our data segment
- mov ds,ax
- mov ax,rarp_stackid.pstack ; StackID for ecb structure
- mov rcvtype,rarp_type ; store protocol TYPE int
- jmp short arp_common ; do ARP/RARP common code
- rarp_rcvr endp
-
- ; ARP protocol receive service routine, similar to ip_rcvr.
- arp_rcvr proc far
- push bx
- push cx
- push di
- push ds
- mov cx,ds ; DS:SI from LSL
- mov es,cx
- mov ax,DGROUP ; set DS to our data segment
- mov ds,ax
- mov ax,arp_stackid.pstack ; StackID for ecb structure
- mov rcvtype,arp_type ; store protocol TYPE int
-
- arp_common: ; common code for ARP/RARP
- push es
- push si
- cmp tells_len,0 ; have data length available?
- je arp_com1 ; e = no
- les si,es:[di].DataLookAheadDataSize ; ptr to what it says
- mov cx,word ptr es:[si] ; get length of data field
- add cx,4 ; for overzealous board transfers
- pop si
- pop es
- jmp short odircv
-
- arp_com1:les si,es:[di].LookAheadPtr ; point at lookahead ptr for Data
- mov cx,word ptr es:[si+4] ; ARP/RARP pkt header, length bytes
- add cl,ch ; add HA and IP address lengths
- xor ch,ch
- add cl,cl ; for host and target
- adc ch,0
- add cx,8 ; plus ARP/RARP main header
- cmp word ptr es:[si+2],ip_type ; ARP/RARP Protocol type of IP?
- pop si
- pop es
- jne ip_rcvr1 ; ne = invalid, decline
- ; fall through to odircv
- arp_rcvr endp
-
- ; General worker for ip_rcvr, arp_rcvr, rarp_rcvr. These are invoked by the
- ; LSL when their kind of packet arrives. This module creates the ECB and
- ; dispatches it to the LSL. Operating at LSL interrupt level.
- ; ES:DI is ptr to ODI Lookahead structure, DS is our data seg (DGROUP).
- ; AX is stackid for invoked protocol kind, CX is (guessed) pkt length overall.
- ; Rcvtype is the current invoked protocol TYPE (0008h is IP etc).
- ; When done store in the ecb's protocolws array:
- ; dw protocol TYPE (0008h for IP etc)
- ; dw subscript of this ecbr item (for use by odircmp)
- ; dw <unused>,<unused>
- ; Return ES:SI as pointer to a free ecb and AX = 0 to accept pkt, else
- ; return AX = 8001h to decline pkt (and to ignore ES:SI). Set Z flag to
- ; match AX value.
- odircv proc far
- add pstats.PtotalRxPackets,1 ; update ODI statistics counter
- adc pstats.PtotalRxPackets+2,0
- push ax
- push cx
- mov cx,ecbr_qty ; number of receive ecb's
- xor bx,bx ; find a free ecb for this packet
- odircv8:cmp ecbr_busy[bx],0 ; is this ECB free?
- jne odircv9 ; ne = no, try next
- mov ecbr_num,bx ; remember index for end of proc
- mov ax,size ecbstruct ; size of an ecb
- mul bl ; times this subscript
- add ax,offset DGROUP:ecbr ; start of receive ecbs
- mov bx,ax ; offset of free ecb
- pop cx
- pop ax
- jmp short odircv2 ; use ds:[bx] for address of ecb
- odircv9:inc bx ; next byte in busy array
- loop odircv8
- pop cx ; failed to find a free ecbr
- pop ax
-
- odircv1:add pstats.PIgnoredRxPackets,1 ; update ODI statistics counter
- adc pstats.PIgnoredRxPackets+2,0
- mov ax,LSLERR_OUT_OF_RESOURCES ; decline the packet
- or ax,ax ; set Z flag for ODI
- pop ds
- pop di
- pop cx
- pop bx
- ret
- ; ds:[bx] is ptr to a free ecbr
- odircv2:mov [bx].stackid,ax ; StackID from odircv entry points
- mov ax,es:[di].LBoardNum ; boardnum from ProtocolID lookahead
- mov [bx].boardnum,ax ; store in ecbr
- mov ax,rcvtype ; get TYPE from odircv entry points
- mov word ptr [bx].protocolws,ax ; save TYPE for odircmp
- mov ax,ecbr_num ; ecbr index
- mov word ptr [bx].protocolws+2,ax ; save index for odircmp
-
- cmp cx,64 ; min packet for Ethernet + 4 spare
- jae odircv3 ; ae = no padding needed here
- mov cx,64 ; padded min pkt plus 4 spare bytes
- odircv3:push bx ; get a buffer of length CX bytes
- xor ax,ax ; set AX = 0 for PD "get buf" call
- call pdrcvr ; use PD buffer allocator code
- pop bx ; ES:DI = buffer pointer, CX = length
- mov ax,es
- or ax,di ; check for refused pkt (es:di = NULL)
- jz odircv1 ; z = pkt refused (no buffer space)
- add di,6+6+2 ; skip our MAC header for ecb use
- sub cx,6+6+2 ; less same length for MLID
- mov [bx].frag1addr,di ; offset of buffer which MLID sees
- mov ax,es
- mov [bx].frag1addr+2,ax ; seg of buffer
- mov [bx].datalen,cx ; length of buffer for MLID/LSL use
- mov [bx].frag1len,cx ; ditto
- mov ax,DGROUP ; segment of our ecb's
- mov es,ax
- mov si,bx ; return ES:SI pointing to ECB
- mov bx,ecbr_num ; get ecbr index
- mov ecbr_busy[bx],1 ; mark this ecbr as busy
- pop ds
- pop di
- pop cx
- pop bx
- xor ax,ax ; return AX = 0 to accept
- ret
- odircv endp
-
- ; ODI receive-complete call-back routine for use only by the LSL.
- ; Enter with ES:SI pointing at ECB, interrupts are off.
- ; Returns nothing.
- ; There is no guarantee that this routine will be called in the sequence
- ; which packets arrived, so we carry the bookkeeping in the delivered ECB:
- ; TYPE is for Ethernet_II struct results, ecbr_busy is don't-touch interlock.
- ; Note that we have to construct our own "destination" MAC address.
- ; es:[si].status is 0 (success), 8006h (buffer overrun), 8007h (canceled).
- ; StackID field is from LSL, and it's 0ffffh if using Prescan, and undefined
- ; if using Default. The manual says LSL, but not MLID, calls are ok in here.
- odircmp proc far
- push ds
- push ax
- push bx
- push cx
- mov ax,DGROUP
- mov ds,ax ; set ds to our data segment
- cmp es:[si].frag1addr+2,0 ; segment of pkt being confirmed
- je odircmp5 ; e = illegal, ignore this call
- cmp es:[si].status,0 ; check ECB status for failure
- je odircmp1 ; e = success
- mov es:[si].protocolws,0 ; write TYPE of 0 to permit queueing
- odircmp1:push di ; put dest,src,TYPE into pkt buffer
- push es
- push si ; save ecbr's si
- mov cl,byte ptr es:[si].driverws ; kind of destination, from LSL
- mov di,es:[si].frag1addr ; start of our pkt buffer + 6+6+2
- sub di,6+6+2 ; back to start, for our MAC header
- push ds ; WATCH this, presumes ES == DS!
- pop es ; set ES to DS (where pkt buffer is)
- mov si,offset DGROUP:_eth_addr ; our hardware address
- cmp cl,ECB_BROADCAST ; a broadcast?
- jne odircmp2 ; ne = no, use our address
- mov si,offset DGROUP:bcast ; fill with all 1's
- odircmp2:mov cx,3 ; 6 byte addresses to our application
- cld
- rep movsw ; store source address in pkt buffer
- pop si ; recover ecb si
- push si ; save it again
- mov ax,es:[si].protocolws ; get TYPE, from odircv
- lea si,es:[si].immaddr ; offset to MAC address of sender
- mov cx,3 ; three words worth, garbage and all
- rep movsw ; copy to packet buffer
- stosw ; and write TYPE to packet buffer
- pop si
- pop es
- pop di
- mov cx,es:[si].datalen ; length of data field from ecb
- add cx,6+6+2 ; plus space for dest,src,TYPE
- push es ; save ecb's es:si
- push si
- mov si,es:[si].frag1addr ; offset of pkt being confirmed
- sub si,6+6+2 ; adj to beginning, for our MAC header
- mov ax,1 ; set AX = 1 for buffer done call
- call pdrcvr ; do post processing of buffer
- pop si
- pop es
-
- odircmp5:xor ax,ax
- cmp es:[si].frag1addr+2,ax ; segment of pkt being confirmed
- je odircmp6 ; e = illegal, ignore this call
- mov es:[si].frag1addr+2,ax ; clear pkt buffer pointer (seg)
- mov es:[si].protocolws,ax ; clear packet TYPE
- mov bx,es:[si].protocolws+2 ; point to ecb index
- mov ecbr_busy[bx],al ; say this ecb is free now
- odircmp6:pop cx
- pop bx
- pop ax
- pop ds
- ret
- odircmp endp
-
- ; ODI transmission routine
- ; Enter with ds:si pointing at full Ethernet_II packet, cx = length (bytes)
- ; Once sent the ecb belongs to ODI until the xmt-complete routine is called.
- odixmt proc near
- push si
- push di
- push es
- mov ax,ds
- mov es,ax
- cmp ecbx_busy,0 ; is this transmitter ecb free?
- je odixmt8 ; e = yes
- odixmt7:stc ; say failure
- jmp odixmt6 ; abandon
-
- odixmt8:mov ax,cx ; overall Ethernet_II length
- sub ax,6+6+2 ; omit our MAC header
- jc odixmt6 ; c = failure, abandon
- mov ecbx.datalen,ax ; setup ECB overall data
- mov ecbx.frag1len,ax ; and fragment length
-
- mov cx,3 ; three words of dest MAC address
- mov di,offset DGROUP:ecbx.immaddr ; destination address in ecb
- rep movsw ; copy destination MAC address
- add si,6 ; skip source Ethernet address
- lodsw ; get protocol TYPE, move it to AX
- mov ecbx.frag1addr,si ; offset of packet data
- mov si,ds
- mov ecbx.frag1addr+2,si ; segment of packet data
-
- ; Note: Prescan and Default methods use Raw Send: put 0ffffh in StackID
- ; and include the full frame header in the data field. Check MLID
- ; configuration word ModeFlags, MRawSendBit, for Raw Send capability.
-
- cmp ax,ip_type ; IP, 0x0008h?
- jne odixmt1 ; ne = no
- mov si,offset DGROUP:ip_stackid
- jmp short odixmt3
-
- odixmt1:cmp ax,arp_type ; ARP, 0x0608?
- jne odixmt2 ; ne = no
- mov si,offset DGROUP:arp_stackid
- jmp short odixmt3
-
- odixmt2:cmp ax,rarp_type ; RARP, 0x3580?
- jne odixmt7 ; ne = error, do not send
- mov si,offset DGROUP:rarp_stackid
-
- odixmt3:mov cx,5 ; stackid, protid, boardnum
- mov di,offset DGROUP:ecbx.stackid ; get stack ident area
- rep movsw ; copy to ecbx
-
- mov ecbx_busy,1 ; set ECBx busy flag to busy state
- add pstats.PtotalTxPackets,1 ; update ODI statistics counter
- adc pstats.PtotalTxPackets+2,0
-
- mov si,offset DGROUP:ecbx ; set es:si to ECB
- mov bx,PROTSUP_SEND_PACKET ; send it
- call lslsupport ; call LSL with ecbx ptr in es:si
- clc ; success so far, ints are still off
- odixmt6:pop es
- pop di
- pop si
- ret
- odixmt endp
-
- ; ODI transmission-complete processor, for use only by the LSL.
- ; Returns nothing. Unlocks ECB busy flag.
- odixcmp proc far
- push ds
- push ax
- mov ax,DGROUP ; set addressibility
- mov ds,ax
- mov ecbx_busy,0 ; set ECB busy flag to not-busy
- pop ax
- pop ds
- ret
- odixcmp endp
-
- ; ODI Protocol (that's us) Control routine, required, called from outside.
- ; In principle we should have one of these for each protocol (IP, ARP, RARP)
- ; by putting a different StackControlHandler address in registerstk, but I
- ; doubt that anyone is that interested in such detailed counts.
- ; Return AX clear, Z flag set, and ES:SI as table pointer if success, else
- ; return AX with error code and Z flag clear.
- pcontrol proc far
- cmp bx,GET_STACK_CONFIGURATION ; get stack configuration?
- jne pcont1 ; ne = no
- mov si,DGROUP
- mov es,si ; es:si points to configuration table
- mov si,offset DGROUP:pconfig; the table
- xor ax,ax ; set Z flag
- ret
- pcont1: cmp bx,GET_STACK_STATISTICS ; get stack statistics?
- jne pcont2 ; ne = no
- mov si,DGROUP
- mov es,si ; es:si points to statistics table
- mov si,offset DGROUP:pstats ; the table
- xor ax,ax ; set Z flag
- ret
- pcont2: mov ax,LSLERR_OUT_OF_RESOURCES ; other functions, report error
- or ax,ax ; clear Z flag
- ret
- pcontrol endp
-
- _TEXT ends
- end
-
-